vue+TS部分
首先我们下载RecordRtc相关包
npm install recordrtc
接着我们开始进入需要录制的页面
导入相关包
import RecordRTC from "recordrtc";
声明相关变量
<template>
// 其他代码
// 提示弹窗
<QuitDialog ref="quitRef"></QuitDialog>
</template>
let recorder: RecordRTC | null = null;
let recordingStream: MediaStream | null = null;
// 用于提示当离开界面时弹出提示,点击确定:停止录制并跳转,点击取消:取消跳转
const quitRef = ref<InstanceType<typeof QuitDialog> | null>(null);
// 进入页面开始录制,用户需要选择录制区域(无法避免,浏览器隐私限制)
onMounted(() => {
autoStartRecording();
});
// 打开弹窗并传递参数
const openQuitDialog = (url: string) => {
console.log("准备进入弹窗");
const params = {
recorder: recorder,
recordedVideo: undefined,
recordingStream: recordingStream,
url: url
};
quitRef.value?.acceptParams(params);
};
//开始录屏
const autoStartRecording = () => {
console.log("开始录屏");
navigator.mediaDevices
.getDisplayMedia({ video: true })
.then(stream => {
recordingStream = stream; // 保存录制的流
console.log(recordingStream);
recorder = new RecordRTC(stream, {
type: "video"
});
recorder.startRecording();
})
.catch(error => {
console.error("Error accessing screen:", error);
});
};
接着我们开始编写弹窗代码
<template>
<!-- 视频录制弹窗组件 -->
<el-dialog v-model="dialogVisible" title="提示" width="500px" draggable>
<!-- 提示内容 -->
<span>确认退出?点击确认后将自动保存本次操作内容</span>
<!-- 底部按钮区域 -->
<template #footer>
<span class="dialog-footer">
<!-- 取消按钮 -->
<el-button @click="closeDialog">取消</el-button>
<!-- 确认按钮 -->
<el-button type="primary" @click="confirm">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from "vue";
import router from "@/routers";
import RecordRTC from "recordrtc";
import { uploadVideo } from "@/api/modules/upload";
// 弹窗可见状态
const dialogVisible = ref(false);
// 录制相关参数
let recordedVideo: Blob | undefined;
interface DrawerProps {
recorder: RecordRTC | null;
recordingStream: MediaStream | null;
url: string;
}
// 弹窗属性
const drawerProps = ref<DrawerProps>({
recorder: null,
recordingStream: null,
url: ""
});
// 接收父组件传递的参数并显示弹窗
const acceptParams = (params: DrawerProps) => {
console.log("已经进入弹窗");
drawerProps.value = params;
dialogVisible.value = true;
console.log("drawerProps: " + JSON.stringify(drawerProps.value));
};
// 关闭弹窗
const closeDialog = () => {
dialogVisible.value = false;
};
// 返回首页并关闭弹窗
const goHome = (url: string) => {
dialogVisible.value = false;
router.push(url);
};
// 处理确认按钮点击事件
const confirm = async () => {
console.log("drawerProps.value?: " + drawerProps.value);
autoStopRecording();
goHome(drawerProps.value?.url);
};
// 停止录制操作
const autoStopRecording = async () => {
console.log("停止录屏mi");
if (drawerProps.value?.recorder) {
console.log("recorder不为null");
await drawerProps.value?.recorder.stopRecording(() => {
recordedVideo = drawerProps.value?.recorder?.getBlob();
stopScreenSharing(); // 在停止录制时停止屏幕共享
});
}
};
// 下载录制的视频内容
const downloadVideo = async () => {
console.log("开始下载录屏内容");
if (recordedVideo) {
console.log("recordedVideo不为null");
try {
const url = URL.createObjectURL(recordedVideo);
const response = await fetch(url);
const data = await response.blob();
// 创建FormData对象,用于将文件上传到后端
const formData = new FormData();
formData.append("video", data, "recorded-video.webm");
// 上传视频到后端
const result = await uploadVideo(formData);
console.log("result: " + result);
// 创建并点击一个隐藏的<a>标签以触发下载
const a = document.createElement("a");
document.body.appendChild(a);
a.href = url;
a.download = "recorded-video.webm";
a.click();
window.URL.revokeObjectURL(url);
} catch (error) {
console.error("Error uploading video:", error);
}
} else {
console.log("recordedVideo为null");
}
};
// 停止屏幕共享
const stopScreenSharing = () => {
if (drawerProps.value?.recordingStream) {
const tracks = drawerProps.value?.recordingStream.getTracks();
tracks.forEach((track: { stop: () => void }) => track.stop());
}
// 下载录制的视频
downloadVideo();
};
// 暴露acceptParams方法供父组件调用
defineExpose({ acceptParams });
</script>
此时前端的录制,停止录制,客户端本地下载都已完成
接下来是关于JavaSpringBoot后端的代码
@RestController
@RequestMapping("/api")
public class VideoController {
/**
* 上传视频文件接口
*
* @param file 视频文件,通过RequestParam注解获取
* @return ResponseEntity<String> 包含上传结果的响应实体
*/
@PostMapping("/video")
public ResponseEntity<String> uploadVideo(@RequestParam("video") MultipartFile file) {
System.out.println("执行请求");
// 判断文件是否为空
if (file.isEmpty()) {
return ResponseWrapper.responseEntityFail("程序文件为空");
}
// 指定存储目录
String uploadDir = "D:/programSoftware/java/AIDetectCloudPlatform/recordVideo/";
// 获取当前时间作为文件名的一部分
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
String currentDate = dateFormat.format(new Date());
try {
// 获取原始文件名
String originalFileName = file.getOriginalFilename();
// 构建新的文件名,添加时间戳防止文件名冲突
String newFileName = currentDate + originalFileName.substring(originalFileName.lastIndexOf("."));
// 构建文件路径
String filePath = uploadDir + newFileName;
// 创建目标目录(如果不存在)
File directory = new File(uploadDir);
if (!directory.exists()) {
directory.mkdirs();
}
// 保存文件
file.transferTo(new File(filePath));
System.out.println("保存成功");
// 返回成功的响应,包含上传视频的访问URL
return ResponseWrapper.responseEntityAccept("http://localhost:8080/video/" + newFileName);
} catch (IOException e) {
e.printStackTrace();
return ResponseWrapper.responseEntityFail("文件保存失败");
}
}
}
通过以上代码即可接收前端发送来的文件并本地保存