记一次使用vue+element+webUpload 实现分片上传的笔记

 这个是添加的dialog确认已经实现,但是偶尔会出现分片不按照顺序上传也就是偶尔会出现最后一片先上传,导致的问题就是文件上传前后的MD5不一致,后续视频的压缩解码等操作出现异常。所以再后台做了一些判断。

(请仅作参考,此方法还有很多优化的地方)





后台代码

 @SysLog("后台上传视频")
    @PostMapping("/save")
    @RequiresPermissions("video:info:save")
    public R chunkedUpload(final MultipartFile video,
                           final MultipartFile cover,
                           final Integer vestId,
                           final String textIntro,
                           final Integer typeId,
                           final Integer[] topicIds,
                           final String[] topicNames,
                           final String country,
                           final String token,
                           final String id,
                           final String name,
                           final String type,
                           final Date lastModifiedDate,
                           final Integer size,
                           final Integer chunks,
                           final Integer chunk,
                           final String fileMd5,
                           final long chunkSize,
                           final long timestamp) throws IOException {
        logger.info("当前分片的文件 video = {}", video);
        logger.info("当前分片的token token = {}", token);
        logger.info("当前分片的参数 id = {}", id);
        logger.info("当前分片的文件名 name = {}", name);
        logger.info("当前分片的文件类型 type = {}", type);
        logger.info("当前分片的文件最后修改日期 lastModifiedDate = {}", lastModifiedDate);
        logger.info("当前分片的文件体积(字节) size = {}", size);
        logger.info("分片的总片数 chunks = {}", chunks);
        logger.info("当前分片片数 chunk = {}", chunk);
        logger.info("当前分片的文件大小 chunkSize = {}", chunkSize);
        logger.info("文件md5 fileMd5 = {}", fileMd5);
        if (video == null || video.getSize() == 0) {
            return R.error("视频文件不能为空");
        }
        // 视频最大150MB
        if (video.getSize() > MAX_VIDEO_FILE_SIZE_150_MB) {
            return R.error("视频文件大小不得超过150MB");
        }

        //获取文件名
        String originalFilename = video.getOriginalFilename();
        logger.info("分片上传文件的名字 originalFilename = {}", originalFilename);

        RandomAccessFile raFile = null;
        BufferedInputStream inputStream = null;
        File dirFile = null;
        try {
            dirFile = new File(fileTemp, originalFilename);
            //以读写的方式打开目标文件
            raFile = new RandomAccessFile(dirFile, "rw");
            logger.info("分片上传文件位置 raFile.length = {}", raFile.length());

            long position = 0;
            if (chunks != null && chunk != null) {
                position = chunk * chunkSize;
            }

            logger.info("分片上传文件实际开始位置 chunk*chunkSize = {}", position);
            raFile.seek(position);

            inputStream = new BufferedInputStream(video.getInputStream());

            byte[] buf = new byte[1024];
            int length = 0;
            while ((length = inputStream.read(buf)) != -1) {
                raFile.write(buf, 0, length);
            }

            redisTemplate.opsForHash().increment("video_upload_file_chunk", originalFilename + "_" + vestId + "_" + timestamp, 1);

        } catch (Exception e) {
            throw new IOException(e.getMessage());
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (raFile != null) {
                    raFile.close();
                }
            } catch (Exception e) {
                throw new IOException(e.getMessage());
            }
        }

        final Object rcvedChunk = redisTemplate.opsForHash().get("video_upload_file_chunk", originalFilename + "_" + vestId + "_" + timestamp);

        if (chunks != null && Integer.parseInt(rcvedChunk.toString()) < chunks) {
            return R.ok();
        }

        logger.info("视频文件已全部接受完毕: filename = {}, fileMd5 = {}, chunks = {}", originalFilename, fileMd5, chunks);

        try (
                FileInputStream fis = new FileInputStream(fileTemp + "/" + originalFilename);
        ) {

            String md5Hex = DigestUtils.md5Hex(fis);

            logger.info("保存文件的MD5 = {}", md5Hex);

            if (!Objects.equals(md5Hex, fileMd5)) {
                FileUtils.deleteQuietly(dirFile);
                logger.error("MD5不一致");
                return R.error("完整性校验失败, 请重新上传");
            }
        } finally {
            redisTemplate.opsForHash().delete("video_upload_file_chunk", originalFilename + "_" + vestId + "_" + timestamp);
        }

        final CreateVideoInfoReq req = new CreateVideoInfoReq();

        req.setCountry(country);
        req.setCover(cover);
        req.setTextIntro(textIntro);

        // 如果选择了视频话题
        if (topicIds != null && topicIds.length > 0
                && topicNames != null && topicNames.length > 0
                && topicIds.length == topicNames.length) {

            final VideoTopic[] topics = new VideoTopic[topicIds.length];

            for (int i = 0; i < topicIds.length; i++) {
                final VideoTopic topic = new VideoTopic();
                topic.setTopicId(topicIds[i]);
                topic.setTname(topicNames[i]);

                topics[i] = topic;
            }

            req.setTopics(topics);
        }

        req.setVestId(vestId);
        req.setTypeId(typeId);
        req.setVideoFile(dirFile);

        videoInfoService.adminUpload(req, getUser());
        return R.ok();

    }

 第一个代码片段中的css

html,
body,
p,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section,
summary,
time,
mark,
audio,
video,
input {
  margin: 0;
  padding: 0;
  border: none;
  outline: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}

html,
body,
form,
fieldset,
p,
p,
h1,
h2,
h3,
h4,
h5,
h6 {
  -webkit-text-size-adjust: none;
}

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
  display: block;
}

body {
  font-family: arial, sans-serif;
}

ol,
ul {
  list-style: none;
}

blockquote,
q {
  quotes: none;
}

blockquote:before,
blockquote:after,
q:before,
q:after {
  content: '';
  content: none;
}

ins {
  text-decoration: none;
}

del {
  text-decoration: line-through;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

/* ------------ */
#wrapper {
  width: 100%;
  margin: 0 auto;
  height: 35px;
}

.img-preview {
  width: 160px;
  height: 90px;
  margin-top: 1em;
  border: 1px solid #ccc;
}

.cropper-wraper {
  position: relative;
}

.upload-btn {
  background: #ffffff;
  border: 1px solid #cfcfcf;
  color: #565656;
  padding: 10px 18px;
  display: inline-block;
  border-radius: 3px;
  margin-left: 10px;
  cursor: pointer;
  font-size: 14px;

  position: absolute;
  right: 1em;
  bottom: 2em;
}
.upload-btn:hover {
  background: #f0f0f0;
}
.uploader-container {
  width: 100%;
  font-size: 10px;
}

.webuploader-container {
  position: relative;
  width: 100px;
  height: 21px;
  float: left;
}
.webuploader-element-invisible {
  position: absolute !important;
  clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
  clip: rect(1px, 1px, 1px, 1px);
}
.webuploader-pick {
  position: relative;
  display: inline-block;
  cursor: pointer;
  background: #00b7ee;
  padding: 6px 15px;

  color: #fff;
  text-align: center;
  border-radius: 3px;
  overflow: hidden;
}
.webuploader-pick-hover {
  background: #00a2d4;
}

.webuploader-pick-disable {
  opacity: 0.6;
  pointer-events: none;
}
.file-list {
  width: 100%;
}
.selected-video-name {
  font-size: 10px;
  color: grey;
}
div.webuploader-pick {
  width: 120px;
  height: 40px;
  max-height: 50px;
  padding: 1px;
  margin: 0;
  overflow: hidden;
}
#pick div label {
  height: 50px;
  max-height: 50px;
  overflow: hidden;
}

 

你可能感兴趣的:(记一次使用vue+element+webUpload 实现分片上传的笔记)