当前位置: 首页 > news >正文

React + SpringBoot实现图片预览和视频在线播放,其中视频实现切片保存和分段播放

图片预览和视频在线播放

需求描述

实现播放视频的需求时,往往是前端直接加载一个mp4文件,这样做法在遇到视频文件较大时,容易造成卡顿,不能及时加载出来。我们可以将视频进行切片,然后分段加载。播放一点加载一点,这样同一时间内只会加载一小部分的视频,不容易出现播放卡顿的问题。下面是实现方法。

对视频切片使用的是 ffmpeg,可查看我的这个文章安装使用

后端接口处理

后端需要处理的逻辑有

  1. 根据视频的完整地址找到视频源文件
  2. 根据视频名称进行MD5,在同级目录下创建MD5文件夹,用于存放生成的索引文件和视频切片
  3. 前端调用视频预览接口时先判断有没有索引文件
    1. 如果没有,则先将mp4转为ts,然后对ts进行切片处理并生成index.m3u8索引文件,然后删除ts文件
    2. 如果有,则直接读取ts文件写入到响应头,以流的方式返回给浏览器
  4. 加载视频分片文件时会重复调用视频预览接口,需要对请求进来的参数做判断,判断是否是请求的索引还是分片

首先定义好接口,接收一个文件ID获取到对应的文件信息

@ApiOperation("文件预览")
@GetMapping("preview/{fileId}")
public void preview(@PathVariable String fileId, HttpServletResponse response) {if (fileId.endsWith(".ts")) {filePanService.readFileTs(fileId, response);} else {LambdaUpdateWrapper<FilePan> qw = new LambdaUpdateWrapper<>();qw.eq(FilePan::getFileId, fileId);FilePan one = filePanService.getOne(qw);if (ObjectUtil.isEmpty(one)) {throw new CenterExceptionHandler("文件不存在");}filePanService.preview(one, response);}
}

视频信息如下图

image-20240608111547732

在磁盘上对应的视频

image-20240608111647759

数据库中存放是视频信息

image-20240608111720899

当点击视频时,前端会拿到当前的文件ID请求上面定义好的接口,此时 fielId 肯定不是以 ts 结尾,所以会根据这个 fileId 查询数据库中保存的这条记录,然后调用 filePanService.preview(one, response) 方法

preview方法

preview方法主要处理的几个事情

  1. 首先判断文件类型是图片还是视频
  2. 如果是图片是直接读取图片并返回流
  3. 如果是视频
    1. 首先拿到视频名称,对名称进行md5处理,并生成文件夹
    2. 创建视频ts文件,并对ts进行切片和生成索引
  4. 加载分片文件时调用readFileTs方法
/*** 文件预览*/
@Override
public void preview(FilePan filePan, HttpServletResponse response) {// 区分图片还是视频if (FileTypeUtil.isImage(filePan.getFileName())) {previewImg(filePan, response);} else if (FileTypeUtil.isVideo(filePan.getFileName())) {previewVideo(filePan, response);} else {throw new CenterExceptionHandler("该文件不支持预览");}
}/*** 图片预览** @param filePan* @param response*/
private void previewImg(FilePan filePan, HttpServletResponse response) {if (StrUtil.isEmpty(filePan.getFileId())) {return;}// 源文件路径String realTargetFile = filePan.getFilePath();File file = new File(filePan.getFilePath());if (!file.exists()) {return;}readFile(response, realTargetFile);
}/*** 视频预览** @param filePan* @param response*/
private void previewVideo(FilePan filePan, HttpServletResponse response) {// 根据文件名称创建对应的MD5文件夹String md5Dir = FileChunkUtil.createMd5Dir(filePan.getFilePath());// 去这个目录下查看是否有index.m3u8这个文件String m3u8Path = md5Dir + "/" + FileConstants.M3U8_NAME;if (!FileUtil.exist(m3u8Path)) {// 创建视频ts文件createVideoTs(filePan.getFilePath(), filePan.getFileId(), md5Dir, response);} else {// 读取切片文件readFile(response, m3u8Path);}
}// 创建视频切片文件
private void createVideoTs(String videoPath, String fileId, String targetPath, HttpServletResponse response) {// 1.生成ts文件String video_2_TS = "ffmpeg -y -i %s -vcodec copy -acodec copy -bsf:v h264_mp4toannexb %s";String tsPath = targetPath + "/" + FileConstants.TS_NAME;String cmd = String.format(video_2_TS, videoPath, tsPath);ProcessUtils.executeCommand(cmd, false);// 2.创建切片文件String ts_chunk = "ffmpeg -i %s -c copy -map 0 -f segment -segment_list %s -segment_time 60 %s/%s_%%4d.ts";String m3u8Path = targetPath + "/" + FileConstants.M3U8_NAME;cmd = String.format(ts_chunk, tsPath, m3u8Path, targetPath, fileId);ProcessUtils.executeCommand(cmd, false);// 删除index.ts文件FileUtil.del(tsPath);// 读取切片文件readFile(response, m3u8Path);
}// 加载视频切片文件
@Override
public void readFileTs(String tsFileId, HttpServletResponse response) {String[] tsArray = tsFileId.split("_");String videoFileId = tsArray[0];LambdaUpdateWrapper<FilePan> qw = new LambdaUpdateWrapper<>();qw.eq(FilePan::getFileId, videoFileId);FilePan one = this.getOne(qw);// 获取文件对应的MD5文件夹地址String md5Dir = FileChunkUtil.createMd5Dir(one.getFilePath());// 去MD5目录下读取ts分片文件String tsFile = md5Dir + "/" + tsFileId;readFile(response, tsFile);
}

用到的几个工具类代码

FileTypeUtil

package com.szx.usercenter.util;/*** @author songzx* @create 2024-06-07 13:39*/
public class FileTypeUtil {/*** 是否是图片类型的文件*/public static boolean isImage(String fileName) {String[] imageSuffix = {"jpg", "jpeg", "png", "gif", "bmp", "webp"};String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);for (String s : imageSuffix) {if (s.equals(suffix)) {return true;}}return false;}/*** 是否是视频文件*/public static boolean isVideo(String fileName) {String[] videoSuffix = {"mp4", "avi", "rmvb", "mkv", "flv", "wmv"};String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);for (String s : videoSuffix) {if (s.equals(suffix)) {return true;}}return false;}
}

FileChunkUtil

package com.szx.usercenter.util;import cn.hutool.core.io.FileUtil;
import cn.hutool.crypto.digest.MD5;import java.io.File;/*** 文件上传后的各种处理操作* @author songzx* @create 2024-06-07 13:25*/
public class FileChunkUtil {/*** 合并完文件后根据文件名称创建MD5目录* 用于存放文件缩略图*/public static String createMd5Dir(String filePath) {File targetFile = new File(filePath);String md5Dir = MD5.create().digestHex(targetFile.getName());String targetDir = targetFile.getParent() + File.separator + md5Dir;FileUtil.mkdir(targetDir);return targetDir;}
}

readFile

/*** 读取文件方法** @param response* @param filePath*/
public static void readFile(HttpServletResponse response, String filePath) {OutputStream out = null;FileInputStream in = null;try {File file = new File(filePath);if (!file.exists()) {return;}in = new FileInputStream(file);byte[] byteData = new byte[1024];out = response.getOutputStream();int len = 0;while ((len = in.read(byteData)) != -1) {out.write(byteData, 0, len);}out.flush();} catch (Exception e) {e.printStackTrace();} finally {if (out != null) {try {out.close();} catch (IOException e) {e.printStackTrace();}}if (in != null) {try {in.close();} catch (IOException e) {e.printStackTrace();}}}
}

ProcessUtils

这个方法用于执行CMD命令

package com.szx.usercenter.util;import com.szx.usercenter.handle.CenterExceptionHandler;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;/*** 可以执行命令行命令的工具** @author songzx* @create 2024-06-06 8:56*/
public class ProcessUtils {private static final Logger logger = LoggerFactory.getLogger(ProcessUtils.class);public static String executeCommand(String cmd, Boolean outPrintLog) {if (StringUtils.isEmpty(cmd)) {logger.error("--- 指令执行失败!---");return null;}Runtime runtime = Runtime.getRuntime();Process process = null;try {process = Runtime.getRuntime().exec(cmd);// 取出输出流PrintStream errorStream = new PrintStream(process.getErrorStream());PrintStream inputStream = new PrintStream(process.getInputStream());errorStream.start();inputStream.start();// 获取执行的命令信息process.waitFor();// 获取执行结果字符串String result = errorStream.stringBuffer.append(inputStream.stringBuffer + "\n").toString();// 输出执行的命令信息if (outPrintLog) {logger.info("执行命令:{},已执行完毕,执行结果:{}", cmd, result);} else {logger.info("执行命令:{},已执行完毕", cmd);}return result;} catch (Exception e) {e.printStackTrace();throw new CenterExceptionHandler("命令执行失败");} finally {if (null != process) {ProcessKiller processKiller = new ProcessKiller(process);runtime.addShutdownHook(processKiller);}}}private static class ProcessKiller extends Thread {private Process process;public ProcessKiller(Process process) {this.process = process;}@Overridepublic void run() {this.process.destroy();}}static class PrintStream extends Thread {InputStream inputStream = null;BufferedReader bufferedReader = null;StringBuffer stringBuffer = new StringBuffer();public PrintStream(InputStream inputStream) {this.inputStream = inputStream;}@Overridepublic void run() {try {if (null == inputStream) {return;}bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line = null;while ((line = bufferedReader.readLine()) != null) {stringBuffer.append(line);}} catch (Exception e) {logger.error("读取输入流出错了!错误信息:" + e.getMessage());} finally {try {if (null != bufferedReader) {bufferedReader.close();}if (null != inputStream) {inputStream.close();}} catch (IOException e) {logger.error("关闭流时出错!");}}}}
}

前端方法实现

前端使用的是React

定义图片预览组件 PreviewImage

import React, { forwardRef, useImperativeHandle } from 'react';
import {DownloadOutlined,UndoOutlined,RotateLeftOutlined,RotateRightOutlined,SwapOutlined,ZoomInOutlined,ZoomOutOutlined,
} from '@ant-design/icons';
import { Image, Space } from 'antd';const PreviewImage: React.FC = forwardRef((props, ref) => {const [src, setSrc] = React.useState('');const showPreview = (fileId: string) => {setSrc(`/api/pan/preview/${fileId}`);document.getElementById('previewImage').click();};useImperativeHandle(ref, () => {return {showPreview,};});const onDownload = () => {fetch(src).then((response) => response.blob()).then((blob) => {const url = URL.createObjectURL(new Blob([blob]));const link = document.createElement('a');link.href = url;link.download = 'image.png';document.body.appendChild(link);link.click();URL.revokeObjectURL(url);link.remove();});};return (<Imageid={'previewImage'}style={{ display: 'none' }}src={src}preview={{toolbarRender: (_,{transform: { scale },actions: {onFlipY,onFlipX,onRotateLeft,onRotateRight,onZoomOut,onZoomIn,onReset,},},) => (<Space size={12} className="toolbar-wrapper"><DownloadOutlined onClick={onDownload} /><SwapOutlined rotate={90} onClick={onFlipY} /><SwapOutlined onClick={onFlipX} /><RotateLeftOutlined onClick={onRotateLeft} /><RotateRightOutlined onClick={onRotateRight} /><ZoomOutOutlined disabled={scale === 1} onClick={onZoomOut} /><ZoomInOutlined disabled={scale === 50} onClick={onZoomIn} /><UndoOutlined onClick={onReset} /></Space>),}}/>);
});export default PreviewImage;

定义视频预览组件

视频预览用到了 dplayer ,安装

pnpm add dplayer hls.js
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import DPlayer from 'dplayer';
import './style/video-model.less';const Hls = require('hls.js');const PreviewVideo = forwardRef((props, ref) => {let dp = useRef();const [modal2Open, setModal2Open] = useState(false);const [fileId, setFileId] = useState('');const showPreview = (fileId) => {setFileId(fileId);setModal2Open(true);};const hideModal = () => {setModal2Open(false);};const clickModal = (e) => {if (e.target.dataset.tagName === 'parentBox') {hideModal();}};useEffect(() => {if (modal2Open) {console.log(fileId, 'videovideovideo');dp.current = new DPlayer({container: document.getElementById('video'), // 注意:这里一定要写div的domlang: 'zh-cn',video: {url: `/api/pan/preview/${fileId}`, // 这里填写.m3u8视频连接type: 'customHls',customType: {customHls: function (video) {const hls = new Hls();hls.loadSource(video.src);hls.attachMedia(video);},},},});dp.current.play();}}, [modal2Open]);useImperativeHandle(ref, () => {return {showPreview,};});return (<>{modal2Open && (<div className={'video-box'} data-tag-name={'parentBox'} onClick={clickModal}><div id="video"></div><button className="ant-image-preview-close" onClick={hideModal}><span role="img" aria-label="close" className="anticon anticon-close"><svgfill-rule="evenodd"viewBox="64 64 896 896"focusable="false"data-icon="close"width="1em"height="1em"fill="currentColor"aria-hidden="true"><path d="M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z"></path></svg></span></button></div>)}</>);
});export default PreviewVideo;

父组件引入并使用

import PreviewImage from '@/components/Preview/PreviewImage';
import PreviewVideo from '@/components/Preview/PreviewVideo';const previewRef = useRef();
const previewVideoRef = useRef();// 点击的是文件
const clickFile = async (item) => {// 预览图片if (isImage(item.fileType)) {previewRef.current.showPreview(item.fileId);return;}// 预览视频if (isVideo(item.fileType)) {previewVideoRef.current.showPreview(item.fileId);return;}message.error('暂不支持预览该文件');
};// 点击的文件夹
const clickFolder = (item) => {props.pushBread(item);  // 更新面包屑
};// 点击某一行时触发
const clickRow = (item: { fileType?: string }) => {if (item.fileType) {clickFile(item);} else {clickFolder(item);}
};<PreviewImage ref={previewRef} />
<PreviewVideo ref={previewVideoRef} />

判断文件类型的方法

// 判断文件是否为图片
export function isImage(fileType): boolean {const imageTypes = ['.jpg', '.png', '.jpeg', '.gif', '.bmp', '.webp']return imageTypes.includes(fileType);
}// 判断是否为视频
export function isVideo(fileType): boolean {const videoTypes = ['.mp4', '.avi', '.rmvb', '.mkv', '.flv', '.wmv']return videoTypes.includes(fileType);
}

实现效果

图片预览效果

image-20240608121403097

视频预览效果

image-20240608121438971

并且在播放过程中是分段加载的视频

image-20240608121550836

查看源文件,根据文件名创建一个MD5的文件夹

image-20240608121012668

文件夹中对视频进行了分片处理,每一片都是以文件ID开头,方便加载分片时找到分片对应的位置

image-20240608121809812

相关文章:

React + SpringBoot实现图片预览和视频在线播放,其中视频实现切片保存和分段播放

图片预览和视频在线播放 需求描述 实现播放视频的需求时&#xff0c;往往是前端直接加载一个mp4文件&#xff0c;这样做法在遇到视频文件较大时&#xff0c;容易造成卡顿&#xff0c;不能及时加载出来。我们可以将视频进行切片&#xff0c;然后分段加载。播放一点加载一点&am…...

Suse Linux ssh配置免密后仍需要输入密码

【问题描述】 Suse Linux已经配置了ssh免密&#xff0c;但无法ssh到目标服务器。 对自身的ssh登陆也需要输入密码。 系统–Suse 15 SP5 【重现步骤】 1.使用ssh-keygen -t rsa生产key文件 2.使用ssh-copy-id拷贝public key到目标机器(或者自身) 3.配置成功后ssh 目标时仍需要输…...

apifox 生成签名

目录 前言准备编写签名脚本签名说明捋清思路编码获取签名所需的参数生成签名将签名放到合适的位置完整代码 在apifox中配置脚本新增公共脚本引用公共脚本添加环境变量 参考 前言 略 准备 查看apifox提供的最佳实践文章&#xff1a;接口签名如何处理 编写签名脚本 签名说明…...

介绍建造者模式

建造者模式 将一个复杂对象的创建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示 四种角色 Product 产品角色 指的是一个具体的产品对象Builder 抽象建造者 创建一个产品对象的各个部件的接口/抽象类ConcreteBuilder 具体建造者 实现或继承抽象建造者接口…...

【全部更新完毕】2024全国大学生数据统计与分析竞赛B题思路代码文章教学数学建模-电信银行卡诈骗的数据分析

电信银行卡诈骗的数据分析 摘要 电信银行卡诈骗是当前社会中严重的犯罪问题&#xff0c;分析电信银行卡交易数据&#xff0c;找出高风险交易特征&#xff0c;建立预测模型&#xff0c;将有助于公安部门和金融机构更好地防范诈骗行为&#xff0c;保障用户的财产安全。 针对问…...

【应用浅谈】Odoo的库存计价与产品成本(三)

序言:时间是我们最宝贵的财富,珍惜手上的每个时分 Odoo的库存&#xff08;Stock&#xff09;模块拥有众多功能&#xff0c;其中库存计价是一项非常重要的功能&#xff0c;原生的成本方法分三种&#xff1a;【标准成本】&#xff0c;【平均成本】&#xff0c;【先进先出】&#…...

数据结构之ArrayList与顺序表(下)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 目录 ArrayList的具体使用 118. 杨辉三角 扑克洗牌算法 接上篇&#xff1a;数据结构之ArrayLis…...

openi启智社区 aarch64 npu环境安装飞桨paddlepaddle和PaddleNLP(失败)

以前在启智社区都是编译安装飞桨&#xff0c;这回看到飞桨提供了npu安装包&#xff0c;兴冲冲的以为安装很简单。 之所以安装飞桨&#xff0c;是因为想在启智社区的启智大脑调试环境使用最新的PaddleNLP&#xff0c;结果报错&#xff1a;No module named paddle.nn.layer.laye…...

【漏洞复现】多客圈子论坛系统 httpGet 任意文件读取漏洞

0x01 产品简介 多客圈子论坛系统是一种面向特定人群或特定话题的社交网络&#xff0c;它提供了用户之间交流、分享、讨论的平台。在这个系统中&#xff0c;用户可以创建、加入不同的圈子&#xff0c;圈子可以是基于兴趣、地域、职业等不同主题的。用户可以在圈子中发帖、评论、…...

46-1 护网溯源 - 钓鱼邮件溯源

一、客户提供钓鱼邮件样本 二、行为分析 三、样本分析 对钓鱼邮件中的木马程序1111.exe文件进行了分析,提交了360安全大脑沙箱云和微步在线云沙箱。 360安全大脑沙箱云显示,该1111.exe文件存在危险,因此在解压时需要谨慎操作,以免触发木马程序。 建议使用360压缩软件进行…...

鸿蒙低代码开发一个高频问题

在版本是DevEco Studio 3.1.1 Release&#xff0c;SDK是3.1.0(API9)。 创建和设计的visual文件经常会遇到无法渲染的情况&#xff0c;或者自定义组件在Custom列表中突然不见了的情况。 有以下报错信息的&#xff1a; JSON schema validation error: data/visualModel/value/…...

关于使用南墙waf防护halo网站主页请求404报错的解决方案

文章目录 环境说明问题展示原因探究解决方法 环境说明 在1panel应用商店&#xff0c;部署南墙waf(docker版)halo(2.16.1社区版)注意部署过程中注意uuwaf必须勾选允许外部访问&#xff0c;halo可以不勾选[这里为了证明确实是南墙waf的原因&#xff0c;选择勾选] 问题展示 使…...

Elasticsearch 认证模拟题 - 13

一、题目 集群中有索引 task3&#xff0c;用 oa、OA、Oa、oA 查询结构是 4 条&#xff0c;使用 dingding 的查询结果是 1 条。通过 reindex 索引 task3 为 task3_new&#xff0c;能够使 task3_new 满足以下查询条件。 使用 oa、OA、Oa、oA、0A、dingding 查询都能够返回 6 条…...

Day25 首页待办事项及备忘录添加功能

​ 本章节,完成首页待办事项及备忘录添加功能 一.修改待办事项和备忘录逻辑处理类,即AddMemoViewModel和AddTodoViewModel 在 AddMemoViewModel逻辑处理类中,为了支持与其关联的View视图文件的数据绑定,需要定义一个与视图文件相匹配的实体类 Model。这个Model将包含 View中…...

SpringBoot——全局异常处理

目录 异常 项目总结 新建一个SpringBoot项目 pom.xml Result&#xff08;通用的响应结果类&#xff09; MyBusinessException自定义异常类 GlobalExceptionHandler全局异常处理类 ExceptionController控制器 SpringbootExceptionApplication启动类 参考文章&#xff1a…...

SpringBoot+Vue教师工作量管理系统(前后端分离)

技术栈 JavaSpringBootMavenMySQLMyBatisVueShiroElement-UI 角色对应功能 教师管理员 功能截图...

华为OD技术面试-最长回文串-2024手撕代码真题

题目:最长回文串 给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的 回文串 的长度。 在构造过程中,请注意 区分大小写 。比如 "Aa" 不能当做一个回文字符串。 示例 1: 输入:s = "abccccdd" 输出:7 解释: 我们可以构造的最…...

Python实现连连看8

4 游戏开始 连连看游戏实际上主要完成的是对玩家鼠标点击事件的处理,也就是对鼠标点击事件的响应。 4.1 添加鼠标点击事件响应 在“1.3.4 在窗口上铺设画布”中提到的将画布pack()到窗口代码之前,写入如下代码,其功能是为鼠标点击事件添加响应。 canvas.bind(<Button…...

[Cloud Networking] Layer Protocol (continue)

文章目录 1. STP / RSTP / MSTP Protocol1.1 STP的作用1.2 STP 生成树算法的三个步骤1.3 STP缺点 2. ARP Protocol3. DHCP Protocol3.1 DHCP 三种分配方式3.2 DHCP 攻击 4. IPSEC / MACSEC 1. STP / RSTP / MSTP Protocol 1.1 STP的作用 消除二层环路&#xff1a;通过阻断冗余…...

人工智能在交通与物流领域的普及及应用

文章目录 &#x1f40b;引言 &#x1f40b;自动驾驶 &#x1f988;自动驾驶汽车 &#x1f421;应用现状 &#x1f421;技术实现 &#x1f421;实现过程及代码 &#x1f40b;智能交通管理 &#x1f988;应用现状 &#x1f988;技术实现 &#x1f988;实现过程及代码 &…...

JVM学习-详解类加载器(二)

双亲委派机制 双亲委派优势 避免类的重复加载&#xff0c;确保一个类的全局唯一性 Java类随着它的类加载器一起具备了一种带有优先级的层次关系&#xff0c;通过这种层次关系可以避免类的重复加载&#xff0c;当父类已经加载了该类&#xff0c;就没有必要子ClassLoader再加载…...

数字校园的优势有哪些

数字化时代下&#xff0c;数字校园已成为教育领域一股显著趋势。数字校园旨在借助信息技术工具对传统校园进行改造&#xff0c;提供全新的教学、管理和服务方式。那么&#xff0c;数字校园究竟具备何种优势&#xff1f;现从三个方面为您详细介绍。 首先&#xff0c;数字校园为教…...

DexCap——斯坦福李飞飞团队泡茶机器人:更好数据收集系统的原理解析、源码剖析

前言 2023年7月&#xff0c;我司组建大模型项目开发团队&#xff0c;从最开始的论文审稿&#xff0c;演变成目前的两大赋能方向 大模型应用方面&#xff0c;以微调和RAG为代表 除了论文审稿微调之外&#xff0c;目前我司内部正在逐一开发论文翻译、论文对话、论文idea提炼、论…...

【Mtk Camera开发学习】01 MTK 平台Camera BringUp

本专栏内容针对 “知识星球”成员免费&#xff0c;欢迎关注公众号&#xff1a;小驰行动派&#xff0c;加入知识星球。 #MTK Camera开发学习系列 #小驰私房菜 这篇文章主要介绍MTK 平台&#xff0c;Camera BringUp会涉及到修改的模块。 MTK不同的平台系列&#xff0c;具体修改…...

新能源汽车内卷真相

导语&#xff1a;2025年&#xff0c;我国新能源汽车总产能预计可达3661万辆&#xff0c;如此产能如何消化&#xff1f; 文 | 胡安 “这样卷下去不是办法&#xff0c;企业目的是什么&#xff1f;是盈利&#xff0c;为国家作贡献&#xff0c;为社会作贡献。我们应该有大格局&…...

C 语言实现在终端里输出二维码

Mac 环境安装二维码库 brew install qrencode安装过程报权限问题执行以下命令 sudo chown -R 用户名 /usr/local/include /usr/local/lib chmod uw /usr/local/include /usr/local/lib#include <stdio.h> #include <qrencode.h>void print_qr_code(QRcode *qrcode…...

nodejs---fs模块,文件读写操作详解,自定义一个文件写入方法

fs模块导入 Node.js 同时支持 CommonJS 和 ES 模块系统&#xff08;自 Node.js v12 以来&#xff09; // 两种模块导入方式 import * as fs from fs;// Es6:这种方式需要在package.json中配置"type": "module" const fs require(fs);// commonJs:如果你…...

Linux(Rocky)下 如何输入中文(切换中文输入法)教程

RockyLinux如何输入中文&#xff08;切换中文输入法&#xff09; 注意 在字符画界面的Linux系统中 默认不具备中文输入法的功能 需要SSH或其他远程工具来实现 问题 可能大家有的时候安装了一个虚拟机之后 想切换中文输入法 但是一直找不到方法 下面将利用Rocky9.2作为演示…...

Python中包(package)与模块(module)的概念 以及 import 问题

目录 Python中 包(package) 与 模块(module) 的概念一. Python中, 包 (package) 与 模块 (module) 的概念1. 一个有 __init__.py 文件 的目录, 被视为一个 Python 的 包 (package)2. 一个Python源文件 , 被视为一个模块 (module) 二. 不同包之间 以及 同一个包的不同模块之间的…...

Android常见内存泄漏场景总结

一、非静态内部类造成的内存泄漏 造成原因&#xff1a;非静态内部类默认会持有外部类的引用&#xff0c;如果内部类的生命周期超过了外部类就会造成内存泄漏。 场景&#xff1a;当Activity销毁后&#xff0c;由于内部类中存在异步耗时任务还在执行&#xff0c;导致Activity实…...

公司网站建设工作重点/提高网站搜索排名

问题描述 今天在设计python串口代码时遇见一个问题&#xff0c;接收到的数据打印出来&#xff0c;一直都是两三组连在一起&#xff0c;即我的目标数据是&#xff1a; 7e307d02087d01557e 但是我把接收到的数据经过处理打印出来后是&#xff1a;7e307d02087d01557e7e307d02087d…...

动态网站开发技术php/百度163黄页关键词挖掘

Ⅰ考查目标 计算机学科专业基础综合考试涵盖数据机构、计算机组成原理、操作系统和计算机网络等学科专业基础课程。要求考生比较系统地掌握上述专业基础课程的概念、基本原理和方法&#xff0c;能够运用所学的基本原理和基本方法分析、判断和解决有关理论问题和实际问题。 Ⅱ…...

网站开发风险协议/网络市场调研的方法

1.配置容器注册表 &#xff08;1&#xff09;posman使用主机系统上的registries.conf文件来获取有关它可以使用的容器注册表的信息。文件中[registries.insecure]部分中列出了不安全的注册表。 &#xff08;2&#xff09;podman info命令&#xff1a;显示Podman的配置消息&am…...

毕业设计网站代做多少钱/爱站

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid4902 题目的意思很是简单&#xff0c;一系列的数。 两种操作&#xff1a;1.[l,r]内变为x。2.[l,r]内大于x的变为gcd(a[i],x)。时限15000mm&#xff0c;很有暴力的诱惑力。 不过纯暴力肯定会TLE的。但是&#…...

怎么做网站音乐/免费的模板网站

项目中使用了Lombok&#xff0c;这次升级之后&#xff0c;出现了如下问题&#xff1a; Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of XXXXXXX(no Creators, like default construct, exist): can not deserialize from O…...

wordpress一栏主题/阿里巴巴推广

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 基于用户的协同过滤推荐&#xff08;User-based CF&#xff09;的原理假设&#xff1a;跟你喜好相似的人…...