java大视频分片上传

实现原理,前端控制每次上传1mb,后端接受1mb,并记录该分片下标,返回给前端还未上传的下标,直到所有的都上传完成

controller

@ApiOperation(value = "上传视频", notes = "上传视频", httpMethod = "POST", response = WebResult.class)
@PostMapping(value = "/uploadVideo", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)//
public AjaxResult uploadVideo(@RequestParam(name = "file") MultipartFile file,@RequestParam(name = "chunkIndex") Integer chunkIndex,@RequestParam(name = "md5") String md5,@RequestParam(name = "totalFileSize") Long totalFileSize,@RequestParam(name = "fileName") String fileName,@RequestParam(name = "userName") String userName,HttpServletRequest request) throws Exception {if (null == file || file.isEmpty()) {return AjaxResult.error("文件内容不能为空!");}return fileSystemService.uploadVideo(file, chunkIndex, md5, fileName, userName);}

service

public AjaxResult uploadVideo(MultipartFile file, Integer chunkIndex, String md5, String fileName, String userName) throws IOException {//创建存放文件夹String date = DateTime.now().toString("yyyyMMdd");String dirPath = ConstantUtils.FILE_VIDEO_PATH + userName + "/" + date + "/" + md5 + "/";File dirFile = new File(dirPath);if (!dirFile.exists()){dirFile.mkdirs();}//分区文件String relativeFilePath = dirPath + fileName;File tempFile = new File(relativeFilePath);RandomAccessFile rw = new RandomAccessFile(tempFile, "rw");//定位到分片的偏移量rw.seek(Long.parseLong(ConstantUtils.FILE_VIDEO_CHUNK_SIZE) * chunkIndex);//写入分片数据rw.write(file.getBytes());//关闭流rw.close();//读取已经分片的集合Set<Object> hasChunkList = new HashSet<>();String hasChunkKey = ConstantUtils.CHUNK_PREFIX + md5;if (redisHelper.hasKey(hasChunkKey)){Object o = redisHelper.get(hasChunkKey);JSONArray array = JSONUtil.parseArray(o);hasChunkList.addAll(array);}hasChunkList.add(chunkIndex);//最新分片下标跟新到redisredisHelper.set(hasChunkKey,hasChunkList);HashMap<String, Object> map = new HashMap<>();map.put("url",userName + "/" + date + "/" + md5 + "/" + fileName);map.put("hasList",hasChunkList);return AjaxResult.success(map);}

ConstantUtils

package com.ruoyi.file.utils;import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** @author csb* @description: 获取配置文件常量数据* @date 2023/9/20*/// spring初始化bean的时候,如果bean实现了InitializingBean接口,
// 会自动调用afterPropertiesSet方法
@Component
public class ConstantUtils implements InitializingBean {@Value("${file.video.videoPath}")String videoPath;@Value("${file.video.chunkSize}")String videoChunkSize;public static String FILE_VIDEO_PATH;public static String FILE_VIDEO_CHUNK_SIZE;public static String CHUNK_PREFIX = "FILE_VIDEO";@Overridepublic void afterPropertiesSet() throws Exception {FILE_VIDEO_PATH = videoPath;FILE_VIDEO_CHUNK_SIZE = videoChunkSize;}
}

RedisHelper

package com.ruoyi.file.utils;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;@Component
public class RedisHelper {private static final Logger logger = LoggerFactory.getLogger(RedisHelper.class);public static final int CACHE_TIME_1_YEAR = 60 * 60 * 24 * 365;@Resourceprivate RedisTemplate<Object, Object> redisTemplate;/*** 读取缓存** @param key* @return*/public Object get(final String key) {return redisTemplate.opsForValue().get(key);}/*** 写入缓存*/public boolean set(final String key, Object value) {boolean result = false;try {redisTemplate.opsForValue().set(key, value);result = true;} catch (Exception e) {logger.warn("", e);}return result;}/*** 写入缓存*/public boolean set(final String key, Object value, int seconds) {boolean result = false;try {if (seconds > 0) {redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);} else {redisTemplate.opsForValue().set(key, value);}result = true;} catch (Exception e) {logger.warn("", e);}return result;}public boolean hasKey(String key) {return redisTemplate.hasKey(key);}public boolean exist(final String key) {return redisTemplate.hasKey(key);}/*** 更新缓存*/public boolean getAndSet(final String key, Object value) {boolean result = false;try {redisTemplate.opsForValue().getAndSet(key, value);result = true;} catch (Exception e) {logger.warn("", e);}return result;}/*** 删除缓存*/public boolean delete(final String key) {boolean result = false;try {redisTemplate.delete(key);result = true;} catch (Exception e) {logger.warn("", e);}return result;}/*** 1.Redis设置多个值* 命令:HMSET myhash total 15 success 0 time "2019-12-01 11:10:15"* 2.当一个任务完成之后,把成功的次数加1* 命令:HINCRBY myhash success 1* <p>* 当前有多少个计算(有点过几次计算)* 1.列表中添加值* 命令:RPUSH mylist "hello"* 2.获取列表中所有元素* 命令:LRANGE mylist 0 -1*//*** 设置hash值,同时设置多个属性** @param key 键* @param map 多个属性值用map封装* @return*/public boolean hmset(final String key, Map<String, Object> map) {boolean result = false;try {HashOperations<Object, Object, Object> opsForHash = redisTemplate.opsForHash();opsForHash.putAll(key, map);result = true;} catch (Exception e) {logger.warn("", e);}return result;}/*** 自增值,给hash值某个属性自增** @param key   键* @param field 要自增的属性* @param num   自增值的大小,可以为正数负数* @return*/public boolean hincrby(final String key, String field, Integer num) {boolean result = false;try {HashOperations<Object, Object, Object> opsForHash = redisTemplate.opsForHash();opsForHash.increment(key, field, num);result = true;} catch (Exception e) {logger.warn("", e);}return result;}/*** 自增值,给hash值某个属性自增1** @param key   键* @param field 要自增的属性* @return*/public boolean hincrby(final String key, String field) {boolean result = false;try {HashOperations<Object, Object, Object> opsForHash = redisTemplate.opsForHash();opsForHash.increment(key, field, 1);result = true;} catch (Exception e) {logger.warn("", e);}return result;}/*** 获取hash中的所有数据** @param key* @return*/public Map<Object, Object> hgetall(final String key) {Map<Object, Object> entries = new HashMap<>();try {HashOperations<Object, Object, Object> opsForHash = redisTemplate.opsForHash();entries = opsForHash.entries(key);return entries;} catch (Exception e) {logger.warn("", e);}return entries;}/*** list操作,队列右侧添加值** @param key* @param value* @return*/public boolean rpush(final String key, Object value) {boolean result = false;try {ListOperations<Object, Object> opsForList = redisTemplate.opsForList();opsForList.rightPush(key, value);result = true;} catch (Exception e) {logger.warn("", e);}return result;}/*** 获取列表中的所有元素** @param key* @return*/public List<Object> lrange(final String key) {List<Object> range = new ArrayList<>();try {ListOperations<Object, Object> opsForList = redisTemplate.opsForList();range = opsForList.range(key, 0, -1);return range;} catch (Exception e) {logger.warn("", e);}return range;}/*** 删除list中的值** @param key   list的key* @param value 要删除的list中的value* @return*/public boolean lrem(final String key, Object value) {boolean result = false;try {ListOperations<Object, Object> opsForList = redisTemplate.opsForList();opsForList.remove(key, 0, value);result = true;} catch (Exception e) {logger.warn("", e);}return result;}/*** 设置键的过期时间* @param key 键* @param expiredTimeSecond 过期时间(秒)* @return*/public boolean setKeyExpiredTime(String key, Long expiredTimeSecond){return this.redisTemplate.expire(key, expiredTimeSecond,TimeUnit.SECONDS);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/62111.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

webp 网页如何录屏?

工作中正好研究到了一点&#xff1a;记录下这里&#xff1a; 先看下效果&#xff1a; 具体实现代码&#xff1a; &#xfeff; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…

SpringCloud Gateway转发请求到同一个服务的不同端口

SpringCloud Gateway默认不支持将请求路由到一个服务的多个端口 本文将结合Gateway的处理流程&#xff0c;提供一些解决思路 需求背景 公司有一个IM项目&#xff0c;对外暴露了两个端口8081和8082&#xff0c;8081是springboot启动使用的端口&#xff0c;对外提供一些http接口…

SlickGrid复选框

分析 1、先在columns首列添加复选框&#xff1b; 2、在SlickGrid注册刚添加的复选框&#xff1b; 3、添加复选框变化事件&#xff1b; 4、注册按钮点击事件&#xff0c;点击获取已选中的行。 展示 代码 复选框样式&#xff08;CSS&#xff09; .slick-cell-checkboxsel {bac…

摄像头原始数据读取——V4L2(userptr模式,V4L2_MEMORY_USERPTR)

摄像头原始数据读取——V4L2(userptr模式,V4L2_MEMORY_USERPTR) 用户指针方式允许用户空间的应用程序分配内存&#xff0c;并将内存地址传递给内核中的驱动程序。驱动程序直接将数据填充到用户空间的内存中&#xff0c;从而避免了数据的拷贝过程。 流程&#xff1a; 通过VIDI…

浏览器缓存与协商缓存

1. 强缓存&#xff08;Strong Cache&#xff09; 定义 强缓存是指在缓存的资源有效期内&#xff0c;浏览器会直接使用缓存中的数据&#xff0c;而不会发起网络请求。也就是说&#xff0c;浏览器会直接从本地缓存读取资源&#xff0c;不会与服务器进行任何交互。 如何控制强缓…

AI 写作(一):开启创作新纪元(1/10)

一、AI 写作&#xff1a;重塑创作格局 在当今数字化高速发展的时代&#xff0c;AI 写作正以惊人的速度重塑着创作格局。AI 写作在现代社会中占据着举足轻重的地位&#xff0c;发挥着不可替代的作用。 随着信息的爆炸式增长&#xff0c;人们对于内容的需求日益旺盛。AI 写作能够…

RabbitMQ 篇-深入了解延迟消息、MQ 可靠性(生产者可靠性、MQ 可靠性、消费者可靠性)

??博客主页&#xff1a;【_-CSDN博客】** 感谢大家点赞??收藏评论** 文章目录 ???1.0 RabbitMQ 的可靠性 ? ? ? ? 2.0 发送者的可靠性 ? ? ? ? 2.1 生产者重试机制 ? ? ? ? 2.2 生产者确认机制 ? ? ? ? 2.2.1 开启生产者确认机制 ? ? ? ? 2.2…

问:SpringBoot核心配置文件都有啥,怎么配?

在SpringBoot的开发过程中&#xff0c;核心配置文件扮演着至关重要的角色。这些文件用于配置应用程序的各种属性和环境设置&#xff0c;使得开发者能够灵活地定制和管理应用程序的行为。本文将探讨SpringBoot的核心配置文件&#xff0c;包括它们的作用、区别&#xff0c;并通过…

【机器学习】数据集合集!

本文将为您介绍经典、热门的数据集&#xff0c;希望对您在选择适合的数据集时有所帮助。 1 privacy 更新时间&#xff1a;2024-11-26 访问地址: GitHub 描述&#xff1a; 此存储库包含 TensorFlow Privacy&#xff08;一种 Python&#xff09;的源代码 库&#xff0c;其中包…

Linux V4L2框架介绍

linux V4L2框架介绍 V4L2框架介绍 V4L2&#xff0c;全称Video for Linux 2&#xff0c;是Linux操作系统下用于视频数据采集设备的驱动框。它提供了一种标准化的方式使用户空间程序能够与视频设备进行通信和交互。通过V4L2接口&#xff0c;用户可以方便地实现视频图像数据的采…

[网安靶场] [更新中] UPLOAD LABS —— 靶场笔记合集

GitHub - c0ny1/upload-labs: 一个想帮你总结所有类型的上传漏洞的靶场一个想帮你总结所有类型的上传漏洞的靶场. Contribute to c0ny1/upload-labs development by creating an account on GitHub.https://github.com/c0ny1/upload-labs 0x01&#xff1a;UPLOAD LABS 靶场初识…

SpringBoot社团管理:用户体验优化

3系统分析 3.1可行性分析 通过对本社团管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本社团管理系统采用SSM框架&#xff0c;JAVA作为开发语言&#…

org.apache.log4j的日志记录级别和基础使用Demo

org.apache.log4j的日志记录级别和基础使用Demo&#xff0c;本次案例展示&#xff0c;使用是的maven项目&#xff0c;搭建的一个简单的爬虫案例。里面采用了大家熟悉的日志记录插件&#xff0c;log4j。来自apache公司的开源插件。 package com.qian.test;import org.apache.log…

2024年第15届蓝桥杯C/C++组蓝桥杯JAVA实现

目录 第一题握手&#xff0c;这个直接从49累加到7即可&#xff0c;没啥难度&#xff0c;后面7个不握手就好了&#xff0c;没啥讲的&#xff0c;(然后第二个题填空好难&#xff0c;嘻嘻不会&#xff09; 第三题.好数​编辑 第四题0R格式 宝石组合 数字接龙 最后一题:拔河 第…

matlab根据excel表头筛选表格数据

有如下表格需要筛选&#xff1a; 如果要筛选style中的A&#xff0c;color中的F2&#xff0c;num中的3。 代码如下&#xff1a; clear;clc; file_Pathstrcat(F:\csdn\,test1.xlsx); %表格路径、文件名 E1readtable(file_Path,Sheet,1); %读取表格中的字母和数字,1代表第一个…

day05(单片机高级)PCB基础

目录 PCB基础 什么是PCB&#xff1f;PCB的作用&#xff1f; PCB的制作过程 PCB板的层数 PCB设计软件 安装立创EDA PCB基础 什么是PCB&#xff1f;PCB的作用&#xff1f; PCB&#xff08;Printed Circuit Board&#xff09;&#xff0c;中文名称为印制电路板&#xff0c;又称印刷…

【机器学习】——朴素贝叶斯模型

&#x1f4bb;博主现有专栏&#xff1a; C51单片机&#xff08;STC89C516&#xff09;&#xff0c;c语言&#xff0c;c&#xff0c;离散数学&#xff0c;算法设计与分析&#xff0c;数据结构&#xff0c;Python&#xff0c;Java基础&#xff0c;MySQL&#xff0c;linux&#xf…

【Android+多线程】异步 多线程 知识总结:基础概念 / 多种方式 / 实现方法 / 源码分析

1 基本概念 1.1 线程 定义&#xff1a;一个基本的CPU执行单元 & 程序执行流的最小单元 比进程更小的可独立运行的基本单位&#xff0c;可理解为&#xff1a;轻量级进程组成&#xff1a;线程ID 程序计数器 寄存器集合 堆栈注&#xff1a;线程自己不拥有系统资源&#…

Error: Invalid version flag: if 问题排查

问题描述&#xff1a; 国产化系统适配&#xff0c;arm架构的centos 在上面运行docker 启动后需要安装数据库 依赖perl 在yum install -y perl 时提示&#xff1a; “Error: Invalid version flag: if”

华为鸿蒙内核成为HarmonyOS NEXT流畅安全新基座

HDC2024华为重磅发布全自研操作系统内核—鸿蒙内核&#xff0c;鸿蒙内核替换Linux内核成为HarmonyOS NEXT稳定流畅新基座。鸿蒙内核具备更弹性、更流畅、更安全三大特征&#xff0c;性能超越Linux内核10.7%。 鸿蒙内核更弹性&#xff1a;元OS架构&#xff0c;性能安全双收益 万…