• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

大文件分片上传和断点续传

武飞扬头像
奈何201
帮助1

由于java天生缺陷 但是项目需要上传大文件,所以做了一个分片上传,话不多说.............................

UploadFileUtil.java 工具包 utils层

  1.  
    /**
  2.  
    * 分片上传与断点续传
  3.  
    *
  4.  
    * @param multipartFileParam 分片实体
  5.  
    * @param targetPath 目标路径
  6.  
    * @return 待定
  7.  
    */
  8.  
    public ApiResult uploadAppendFile(MultipartFileParam multipartFileParam, String targetPath) {
  9.  
    String[] bin=multipartFileParam.getFileName ().split ("\\.");
  10.  
    Map<String, String> map = new HashMap<>();
  11.  
    if(!bin[1].equals ("bin")){
  12.  
    map.put("result", "文件格式错误");
  13.  
    log.error ("文件格式不对,请检查升级文件");
  14.  
    return ResultUtil.error (map);
  15.  
    }
  16.  
     
  17.  
     
  18.  
     
  19.  
    long chunk = multipartFileParam.getChunkNumber();
  20.  
    long totalChunks = multipartFileParam.getTotalChunks();
  21.  
    long fileSize = multipartFileParam.getFileSize();
  22.  
    String taskId = multipartFileParam.getTaskId();
  23.  
    MultipartFile file = multipartFileParam.getFile();
  24.  
    String fileName = multipartFileParam.getFileName();
  25.  
    // String extName = FileUtil.extName(fileName);
  26.  
    // String separator = FileUtil.FILE_SEPARATOR;
  27.  
    String localPath = targetPath separator;
  28.  
    File tempFile = null;
  29.  
    RandomAccessFile raf = null;
  30.  
    InputStream is = null;
  31.  
    try {
  32.  
    if (chunk == 1) {
  33.  
    String tempFileName = taskId fileName.substring(fileName.lastIndexOf(".")) "_tmp";
  34.  
    File fileDir = new File(localPath);
  35.  
    if (!fileDir.exists()) {
  36.  
    fileDir.mkdirs();
  37.  
    }
  38.  
    tempFile = new File(localPath, tempFileName);
  39.  
    if (!tempFile.exists()) {
  40.  
    tempFile.createNewFile();
  41.  
     
  42.  
    }
  43.  
    raf = new RandomAccessFile(tempFile, "rw");
  44.  
    is = file.getInputStream();
  45.  
    raf.seek(0);
  46.  
    int len = 0;
  47.  
    byte[] bytes = new byte[1024 * 10];
  48.  
    while ((len = is.read(bytes)) != -1) {
  49.  
    raf.write(bytes, 0, len);
  50.  
    }
  51.  
    raf.close();
  52.  
    is.close();
  53.  
    redisUtil.setObject(UpLoadConstant.chunkNum taskId, chunk, cacheTime);
  54.  
    redisUtil.setObject(UpLoadConstant.fastDfsPath taskId, tempFile.getPath(), cacheTime);
  55.  
    map.put("result", "上传成功");
  56.  
    } else {
  57.  
    String path = (String) redisUtil.getObject(UpLoadConstant.fastDfsPath taskId);
  58.  
    is = file.getInputStream();
  59.  
    raf = new RandomAccessFile(path, "rw");
  60.  
    raf.seek(fileSize);
  61.  
    int len = 0;
  62.  
    byte[] bytes = new byte[1024 * 10];
  63.  
    while ((len = is.read(bytes)) != -1) {
  64.  
    raf.write(bytes, 0, len);
  65.  
    }
  66.  
    redisUtil.setObject(UpLoadConstant.chunkNum taskId, chunk, cacheTime);
  67.  
    raf.close();
  68.  
    is.close();
  69.  
    }
  70.  
    String md5 = (String) redisUtil.getObject(UpLoadConstant.task taskId);
  71.  
    HashMap<String, String> redisMap = new HashMap<>();
  72.  
    redisMap.put("fileSize", fileSize "");
  73.  
    redisMap.put("taskId", taskId);
  74.  
     
  75.  
    redisUtil.setHashAsMap(UpLoadConstant.fileMd5 md5, redisMap, cacheTime);
  76.  
    if (chunk == totalChunks) {
  77.  
    String path = (String) redisUtil.getObject(UpLoadConstant.fastDfsPath taskId);
  78.  
    // FileUtil.rename(new File(path), fileName, true);//改文件名称 原名
  79.  
    FileUtil.rename(new File(path), "upgrade.bin", true);//指定名称 upgrade.bin
  80.  
    map.put("result", "上传完毕");
  81.  
    redisUtil.del(UpLoadConstant.fileMd5 md5);
  82.  
    redisUtil.del(UpLoadConstant.task taskId);
  83.  
    redisUtil.del(UpLoadConstant.chunkNum taskId);
  84.  
    redisUtil.del(UpLoadConstant.fastDfsPath taskId);
  85.  
    }
  86.  
    } catch (IOException e) {
  87.  
    e.printStackTrace();
  88.  
    String md5 = (String) redisUtil.getObject(UpLoadConstant.task taskId);
  89.  
    redisUtil.del(UpLoadConstant.fileMd5 md5);
  90.  
    redisUtil.del(UpLoadConstant.task taskId);
  91.  
    redisUtil.del(UpLoadConstant.chunkNum taskId);
  92.  
    redisUtil.del(UpLoadConstant.fastDfsPath taskId);
  93.  
    map.put("result", "上传异常");
  94.  
    } finally {
  95.  
    try {
  96.  
    if (raf != null) {
  97.  
    raf.close();
  98.  
    }
  99.  
    } catch (IOException e) {
  100.  
    e.printStackTrace();
  101.  
    }
  102.  
    try {
  103.  
    if (is != null) {
  104.  
    is.close();
  105.  
    }
  106.  
    } catch (IOException e) {
  107.  
    e.printStackTrace();
  108.  
    }
  109.  
    }
  110.  
    return ResultUtil.success(map);
  111.  
    }
  112.  
     
  113.  
    /**
  114.  
    * 校验md5值
  115.  
    *
  116.  
    * @param md5 md5
  117.  
    * @return map
  118.  
    */
  119.  
    public Map<String, Object> checkMd5(String md5) {
  120.  
    Map<String, Object> map = new HashMap<>();
  121.  
     
  122.  
    String fileSize = "";
  123.  
    String taskId = "";
  124.  
    md5 = SecureUtil.md5(md5);
  125.  
    Map redisMap = redisUtil.getMap(UpLoadConstant.fileMd5 md5);
  126.  
    if (MapUtil.isNotEmpty(redisMap)) {
  127.  
    fileSize = ( redisMap.get("fileSize").toString ());
  128.  
    taskId = ( redisMap.get("taskId").toString ());
  129.  
    }
  130.  
    if (StrUtil.isNotEmpty(fileSize)) {
  131.  
    map.put("fileSize", Long.parseLong(fileSize));
  132.  
    } else {
  133.  
    Map<String, Object> map1 = new HashMap<>();
  134.  
    taskId = IdUtil.simpleUUID();
  135.  
    map1.put("fileSize", 0);
  136.  
    map1.put("taskId", taskId);
  137.  
    redisUtil.setHashAsMap(UpLoadConstant.fileMd5 md5, map1, cacheTime);
  138.  
    redisUtil.setObject(UpLoadConstant.task taskId, md5, cacheTime);
  139.  
    map.put("fileSize", 0);
  140.  
    }
  141.  
    map.put("taskId", taskId);
  142.  
    return map;
  143.  
    }
学新通

RedisUtil.java 同为utils层

  1.  
    package vip.xiaonuo.sys.modular.upgrade.utils;
  2.  
     
  3.  
    import org.springframework.data.redis.core.RedisTemplate;
  4.  
    import org.springframework.stereotype.Component;
  5.  
    import org.springframework.util.CollectionUtils;
  6.  
     
  7.  
    import javax.annotation.Resource;
  8.  
    import java.util.List;
  9.  
    import java.util.Map;
  10.  
    import java.util.concurrent.TimeUnit;
  11.  
     
  12.  
    /**
  13.  
    * @Author: geng
  14.  
    * @Date: 2022/9/23 21:49
  15.  
    * @Description:
  16.  
    */
  17.  
    @Component
  18.  
    public class RedisUtil {
  19.  
     
  20.  
    @Resource
  21.  
    private RedisTemplate<String, Object> redisTemplate;
  22.  
     
  23.  
    //写入对象
  24.  
    public boolean setObject(final String key, Object value, Integer expireTime) {
  25.  
    try {
  26.  
     
  27.  
    redisTemplate.opsForValue().set(key, value);
  28.  
    redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
  29.  
    return true;
  30.  
    } catch (Exception e) {
  31.  
    e.printStackTrace();
  32.  
    return false;
  33.  
    }
  34.  
    }
  35.  
     
  36.  
    //获取对象
  37.  
    public Object getObject(final String key) {
  38.  
    return key == null ? null : redisTemplate.opsForValue().get(key);
  39.  
    }
  40.  
     
  41.  
     
  42.  
    //写入集合
  43.  
    public boolean setList(final String key, Object value, Integer expireTime) {
  44.  
    try {
  45.  
    redisTemplate.opsForList().rightPush(key, value);
  46.  
    redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
  47.  
    return true;
  48.  
    } catch (Exception e) {
  49.  
    e.printStackTrace();
  50.  
    return false;
  51.  
    }
  52.  
    }
  53.  
     
  54.  
    //获取集合
  55.  
    public List<Object> getList(final String key) {
  56.  
    try {
  57.  
    return redisTemplate.opsForList().range(key, 0, -1);
  58.  
    } catch (Exception e) {
  59.  
    e.printStackTrace();
  60.  
    return null;
  61.  
    }
  62.  
    }
  63.  
     
  64.  
    public boolean setHashAsKV(String key, Object hk, Object hv, Integer expireTime) {
  65.  
    try {
  66.  
    redisTemplate.opsForHash().put(key, hk, hv);
  67.  
    redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
  68.  
    return true;
  69.  
    } catch (Exception e) {
  70.  
    e.printStackTrace();
  71.  
    }
  72.  
    return false;
  73.  
    }
  74.  
     
  75.  
    public boolean setHashAsMap(String key, Map map, Integer expireTime) {
  76.  
    try {
  77.  
    redisTemplate.opsForHash().putAll(key, map);
  78.  
    redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
  79.  
    return true;
  80.  
    } catch (Exception e) {
  81.  
    e.printStackTrace();
  82.  
    }
  83.  
    return false;
  84.  
    }
  85.  
     
  86.  
    public Map getMap(String key) {
  87.  
    Map<Object, Object> map = redisTemplate.opsForHash().entries(key);
  88.  
    if (CollectionUtils.isEmpty(map)) {
  89.  
    return null;
  90.  
    }
  91.  
    return map;
  92.  
    }
  93.  
     
  94.  
    public Object getHashObject(String k1, String k2) {
  95.  
    return redisTemplate.opsForHash().get(k1, k2);
  96.  
    }
  97.  
     
  98.  
    /**
  99.  
    * 判断是否存在key
  100.  
    *
  101.  
    * @param key key
  102.  
    * @return
  103.  
    */
  104.  
    public boolean hasKey(final String key) {
  105.  
    try {
  106.  
    return redisTemplate.hasKey(key);
  107.  
    } catch (Exception e) {
  108.  
    e.printStackTrace();
  109.  
    }
  110.  
    return false;
  111.  
    }
  112.  
     
  113.  
    /**
  114.  
    * 删除key
  115.  
    *
  116.  
    * @param key key
  117.  
    * @return
  118.  
    */
  119.  
    public void del(final String key) {
  120.  
    if (hasKey(key)) {
  121.  
    redisTemplate.delete(key);
  122.  
    }
  123.  
    }
  124.  
     
  125.  
    /**
  126.  
    * 批量删除key
  127.  
    *
  128.  
    * @param keys keys
  129.  
    * @return
  130.  
    */
  131.  
    public boolean delKeys(String... keys) {
  132.  
    for (String key : keys) {
  133.  
    if (hasKey(key)) {
  134.  
    Boolean flag = redisTemplate.delete(key);
  135.  
    if (flag == null) {
  136.  
    continue;
  137.  
    }
  138.  
    if (!flag) {
  139.  
    return false;
  140.  
    }
  141.  
    }
  142.  
    }
  143.  
    return true;
  144.  
    }
  145.  
    }
学新通

entity层

  1.  
    package vip.xiaonuo.sys.modular.upgrade.entity;
  2.  
     
  3.  
    import lombok.Data;
  4.  
    import org.springframework.web.multipart.MultipartFile;
  5.  
     
  6.  
    import java.io.Serializable;
  7.  
     
  8.  
    @Data
  9.  
    public class MultipartFileParam implements Serializable {
  10.  
    private static final long serialVersionUID = 3238600879053243080L;
  11.  
    private String taskId;//文件传输任务ID
  12.  
    private long chunkNumber;//当前为第几分片
  13.  
    private long chunkSize;//每个分块的大小
  14.  
    private long totalChunks;//分片总数
  15.  
    private long fileSize;
  16.  
    private String fileName;
  17.  
    private String identifier;//文件唯一标识
  18.  
    private MultipartFile file;//分块文件传输对象
  19.  
     
  20.  
    }
学新通
UpLoadConstant.java constant层
  1.  
    package vip.xiaonuo.sys.modular.upgrade.constant;
  2.  
     
  3.  
    /**
  4.  
    * @Author: geng
  5.  
    * @Date: 2022/9/23 22:00
  6.  
    * @Description:
  7.  
    */
  8.  
    public class UpLoadConstant {
  9.  
    private final static String uploading = "Uploading:";
  10.  
    private final static String file = uploading "file:";
  11.  
    //当前文件传输到第几块
  12.  
    public final static String chunkNum = file "chunkNum:";
  13.  
    //当前文件上传到fastdfs路径
  14.  
    public final static String fastDfsPath = file "fastDfsPath:";
  15.  
    public final static String task = uploading "task:";
  16.  
    public final static String fileMd5 = file "md5:";
  17.  
     
  18.  
    }
学新通

param层

  1.  
    package vip.xiaonuo.sys.modular.upgrade.param;
  2.  
     
  3.  
    /**
  4.  
    * @Author: geng
  5.  
    * @Date: 2022/9/23 22:27
  6.  
    * @Description:
  7.  
    */
  8.  
    public class ApiResult {
  9.  
    /**
  10.  
    * 错误码.
  11.  
    */
  12.  
    private Integer code;
  13.  
     
  14.  
    /**
  15.  
    * 提示信息.
  16.  
    */
  17.  
    private String msg;
  18.  
     
  19.  
    /**
  20.  
    * 具体的内容.
  21.  
    */
  22.  
    private Object data;
  23.  
     
  24.  
    public Integer getCode() {
  25.  
    return code;
  26.  
    }
  27.  
     
  28.  
    public void setCode(Integer code) {
  29.  
    this.code = code;
  30.  
    }
  31.  
     
  32.  
    public String getMsg() {
  33.  
    return msg;
  34.  
    }
  35.  
     
  36.  
    public void setMsg(String msg) {
  37.  
    this.msg = msg;
  38.  
    }
  39.  
     
  40.  
    public Object getData() {
  41.  
    return data;
  42.  
    }
  43.  
     
  44.  
    public void setData(Object data) {
  45.  
    this.data = data;
  46.  
    }
  47.  
    }
学新通
  1.  
    package vip.xiaonuo.sys.modular.upgrade.param;
  2.  
     
  3.  
    public enum CustomResponse {
  4.  
    SUCCESS(10000, "响应成功"),
  5.  
    FAILURE(10001, "响应失败");
  6.  
    private Integer code;
  7.  
    private String msg;
  8.  
     
  9.  
    CustomResponse(Integer code, String msg) {
  10.  
    this.code = code;
  11.  
    this.msg = msg;
  12.  
    }
  13.  
     
  14.  
    public Integer getCode() {
  15.  
    return code;
  16.  
    }
  17.  
     
  18.  
    public String getMsg() {
  19.  
    return msg;
  20.  
    }
  21.  
    }
学新通
  1.  
    package vip.xiaonuo.sys.modular.upgrade.param;
  2.  
     
  3.  
    /**
  4.  
    * @Author: geng
  5.  
    * @Date: 2022/9/23 22:28
  6.  
    * @Description:
  7.  
    */
  8.  
    public class ResultUtil {
  9.  
    public static ApiResult success(Object object) {
  10.  
    ApiResult apiResult = new ApiResult();
  11.  
    apiResult.setCode(CustomResponse.SUCCESS.getCode());
  12.  
    apiResult.setMsg(CustomResponse.SUCCESS.getMsg());
  13.  
    apiResult.setData(object);
  14.  
    return apiResult;
  15.  
    }
  16.  
     
  17.  
    public static ApiResult success() {
  18.  
    ApiResult apiResult = new ApiResult();
  19.  
    apiResult.setCode(CustomResponse.SUCCESS.getCode());
  20.  
    apiResult.setMsg(CustomResponse.SUCCESS.getMsg());
  21.  
    return apiResult;
  22.  
    }
  23.  
     
  24.  
    public static ApiResult success(Integer code, String msg, Object obj) {
  25.  
    ApiResult apiResult = new ApiResult();
  26.  
    apiResult.setCode(code);
  27.  
    apiResult.setMsg(msg);
  28.  
    apiResult.setData(obj);
  29.  
    return apiResult;
  30.  
    }
  31.  
     
  32.  
    public static ApiResult error(Object object) {
  33.  
    ApiResult apiResult = new ApiResult();
  34.  
    apiResult.setCode(CustomResponse.FAILURE.getCode());
  35.  
    apiResult.setMsg(CustomResponse.FAILURE.getMsg());
  36.  
    apiResult.setData(object);
  37.  
    return apiResult;
  38.  
    }
  39.  
     
  40.  
    public static ApiResult errMsg(String msg) {
  41.  
    ApiResult apiResult = new ApiResult();
  42.  
    apiResult.setCode(CustomResponse.FAILURE.getCode());
  43.  
    apiResult.setMsg(msg);
  44.  
    return apiResult;
  45.  
    }
  46.  
     
  47.  
    public static ApiResult error() {
  48.  
    ApiResult apiResult = new ApiResult();
  49.  
    apiResult.setCode(CustomResponse.FAILURE.getCode());
  50.  
    apiResult.setMsg(CustomResponse.FAILURE.getMsg());
  51.  
    return apiResult;
  52.  
    }
  53.  
     
  54.  
    public static ApiResult error(Integer code, String msg, Object obj) {
  55.  
    ApiResult apiResult = new ApiResult();
  56.  
    apiResult.setCode(code);
  57.  
    apiResult.setMsg(msg);
  58.  
    apiResult.setData(obj);
  59.  
    return apiResult;
  60.  
    }
  61.  
    }
学新通

controller层

  1.  
    @GetMapping("/checkMd5")
  2.  
    public ApiResult checkMd5(@Param ("md5") String md5) {
  3.  
    Map<String, Object> map = uploadFileUtil.checkMd5(md5);
  4.  
    return ResultUtil.success(map);
  5.  
    }
  6.  
     
  7.  
    @PostMapping(value = "/chunkUpload")
  8.  
    public ApiResult chunkUpload(MultipartFileParam multipartFileParam) {
  9.  
    return uploadFileUtil.uploadAppendFile(multipartFileParam, "D:\\klp");
  10.  
    }

前端代码

  1.  
    chunkUpload() {
  2.  
     
  3.  
    const file = this.fileList[0]
  4.  
    const md5 = file.name file.size file.lastModified
  5.  
     
  6.  
    chunkUploaMess(md5).then((res)=>{
  7.  
    if (res) {
  8.  
    console.log(res)
  9.  
    const start = Number(res.data.fileSize)
  10.  
    const taskId = res.data.taskId
  11.  
    if (res.data) {
  12.  
     
  13.  
    this.upload(start, taskId, file)
  14.  
    } else {
  15.  
    this.upload(0, taskId, file)
  16.  
    }
  17.  
     
  18.  
    })
  19.  
     
  20.  
    }
学新通
  1.  
    upload(start, taskId, file) {
  2.  
    // 分片大小 5M
  3.  
    const bytePercent = 1024 * 1024 * 5
  4.  
    // 通过文件大小除以分片大小得出总片数
  5.  
    const totalChunks = Math.ceil(file.size / bytePercent)
  6.  
    // 起始位置 分片数 如果大于文件大小,那么终点位置就是文件大小,反之就是前者
  7.  
    const end = (start bytePercent) > file.size ? file.size : (start bytePercent)
  8.  
    const fileName = file.name
  9.  
    // 分片文件
  10.  
    const chunkFile = file.slice(start, end)
  11.  
    // 当前分片数
  12.  
    const currChunkNum =parseInt (start / bytePercent) 1
  13.  
    const formData = new FormData()
  14.  
    formData.append('file', chunkFile)
  15.  
    formData.append('fileName', fileName)
  16.  
    formData.append('fileSize', start)
  17.  
    formData.append('taskId', taskId)
  18.  
    formData.append('chunkNumber', currChunkNum)
  19.  
    formData.append('chunkSize', bytePercent)
  20.  
    formData.append('totalChunks', totalChunks)
  21.  
     
  22.  
    uploadsMess(formData).then((res)=>{
  23.  
    if (res.data.result === '上传完毕') {
  24.  
    alert('成功')
  25.  
    } else {
  26.  
     
  27.  
    this.upload(end, taskId, file)
  28.  
    }
  29.  
    })
  30.  
     
  31.  
     
  32.  
    },
学新通

api

  1.  
    /**
  2.  
    * 分片
  3.  
    * @returns {AxiosPromise}
  4.  
    * @param md5
  5.  
    */
  6.  
    export function chunkUpload(md5) {
  7.  
    return axios({
  8.  
    url: '/main/checkMd5',
  9.  
    method: 'get',
  10.  
    data: md5,
  11.  
    })
  12.  
    }
  13.  
    /**
  14.  
    * 分片
  15.  
    * @returns {AxiosPromise}
  16.  
    * @param formData
  17.  
    */
  18.  
    export function uploads(formData) {
  19.  
    return axios({
  20.  
    url: '/main/chunkUpload',
  21.  
    method: 'POST',
  22.  
    data: formData,
  23.  
    contentType: false,//很重要,指定为false才能形成正确的Content-Type
  24.  
    processData: false, //加入这属性 processData默认为true,为true时,提交不会序列化data。
  25.  
    })
  26.  
    }
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbhhbf
系列文章
更多 icon
同类精品
更多 icon
继续加载