工控行业IO信号Web监控平台原理及技术实现方案

news2026/5/24 13:02:25
本文从实际使用角度出发意在解决行业系统中的IO信号监控痛点。一台设备的 IO 信号点动辄成百上千——从简单的门锁状态、急停按钮到复杂的真空压力模拟量、主轴转速等。这些信号的实时监控直接关系到设备稼动率OEE和良品率Yield。本文从原理层和工程实现层两个维度完整阐述一套 IO 信号监控平台的架构与开发实践。一、前言1.1 行业背景在工业自动化Industrial Automation领域PLC可编程逻辑控制器和SCADA监控与数据采集系统是贯穿整个生产过程的两大支柱。随着工业 4.0 和智能制造战略的推进产线对设备状态的可视化、异常信号的实时告警以及数据的可追溯性提出了越来越高的要求。在半导体、汽车零部件、3C 电子等精密制造行业一台设备的 IO 信号点动辄成百上千——从简单的门锁状态、急停按钮到复杂的真空压力模拟量、主轴转速设定值。这些信号的实时监控直接关系到设备稼动率OEE和良品率Yield。然而传统方案往往依赖昂贵的商用组态软件如 WinCC、Intouch或闭源厂商协议栈存在成本高、定制难、扩展性差的痛点。1.2 本文目标本文从原理层和工程实现层两个维度完整阐述一套 IO 信号监控平台的架构与开发实践。平台采用 Go 语言编写后端原生 HTML/CSS/JavaScript 构建前端依托 Redis 作为信号数据源通过 WebSocket 实现毫秒级实时推送并内嵌可热更新的规则告警引擎。本文不仅记录系统设计思路更重要的是呈现每一块代码背后的工程决策——从数据流模型、去重算法到双周期推送机制希望能为同样从事工控软件开发的同行提供有价值的参考。1.3 架构总览┌─────────────────────────────────────────────────────────┐ │ 前端(Web)│ │ HTML CSS JavaScript 单页应用 │ │ ┌─── 信号看板 ─── 告警日志 ─── 规则管理面板 ───┐ │ │ └──────────────────────┬────────────────────────┘ │ └───────────────────────────┼──────────────────────────────┘ │ WebSocket(ws://) REST API │ ┌───────────────────────────┼──────────────────────────────┐ │ 后端(Go)│ │ │ │ main.go ─── HTTP 路由 REST API 入口 │ │ ├── ws/hub.go ─── WebSocket Hub 分页数据推送 │ │ ├── alarm/ ─── 规则编译、引擎评估、历史存储 │ │ ├── redis/ ─── Redis 客户端批量 MGET 取值 │ │ └── config/ ─── 配置加载、保存、类型定义 │ │ │ │ └────────────────────────────┼──────────────────────────────┘ │ Redis MGET ┌────────┴────────┐ │ Redis 数据源 │ │(第三方写入信号值)│ └─────────────────┘工程源码https://download.csdn.net/download/qq8864/92899106实现效果截图支持查询历史报警信息支持添加报警监控规则支持对AI/DI信号进行曲线图表监控支持自定义仪表盘只关注需要关注的信号1.4 设计理念本系统遵循三条核心设计原则分离原则— 信号定义io.json与运行时配置app.json分离前者描述硬件拓扑后者描述业务逻辑。两者独立版本管理互不耦合。热更新— 告警规则的增删改无需重启服务通过内部引擎 Reload 接口实时生效满足生产线连续运行的要求。最小依赖— 后端仅依赖 Redis 和 SQLite 两个数据组件前端零框架、零构建工具单个 HTML 文件加一个 CSS/JS 即完成交付。1.5 数据流模型Redis(信号值 JSON)──→ MGET 批量读取 │ ┌──────┴──────┐ │ 信号值分发 │ ├──────────────┤ │ ① 推送前端 │──→ WebSocket → 信号卡片实时渲染 │ ② 告警引擎 │──→ 规则评估 → 告警事件推送 └──────────────┘数据流有两个关键特征批量拉取Pull而非订阅Pub/Sub后端以固定周期调用 Redis MGET 批量获取所有信号值避免了 N:M 的 Pub/Sub 通道维护复杂度。双周期隔离信号推送周期默认 150ms和告警评估周期默认 2000ms独立运行高频数据不被低频告警拖累。二、功能特性实时信号看板— 通过 WebSocket 实时推送 DI/AI 信号值支持 Tab 分类显示历史趋势曲线— 内存环形缓冲区存储最近 200 个数据点约 30 秒AI 信号显示蓝色平滑折线图DI 信号显示绿色步进波形图ON/OFF 电平信号关注收藏— 点击信号卡片上的 ★ 星标关注信号过滤器栏支持一键切换仅显示关注模式关注列表自动保存至浏览器分组过滤与搜索— 按信号组区域快速筛选支持信号名称/Key 关键字搜索分页浏览— 自定义每页数量12/24/48/96支持首末页和跳页告警引擎— 基于可配置规则的实时评估DI支持上升沿/下降沿/任意变化AI支持大于/小于/等于/区间比较告警状态机— 内置状态机去重仅状态切换时产生告警避免高频刷屏告警历史— SQLite 持久化存储支持按级别/信号/状态筛选和分页查询规则管理— 前端可视化 CRUD 操作配置实时生效热更新无需重启规则导入/导出— 批量导入/导出 JSON 格式规则文件方便备份和迁移双周期推送— 信号数据短周期默认 150ms与告警事件长周期默认 2000ms独立推送三、信号数据模型与配置体系3.1 双文件配置策略工控现场最常见的痛点之一是配置混乱——IO 映射、规则逻辑、通讯参数混杂在同一个文件中。本系统采用双文件拆分配置文件路径职责变更频率信号定义config/io/io.json描述硬件拓扑DI/AI/DO/AO 的 Key、名称、地址、单位极低产线定型后几乎不变应用配置config/app.jsonRedis 连接、服务端口、告警规则、信号分组中等规则随工艺调整这种分离带来一个实际的收益当产线新增一台设备时只需工程师更新 io.json当工艺参数变化需要调整告警阈值时操作员可直接通过界面 CRUD 而无需动底层的硬件映射。四、技术实现详细方案4.1 为什么选 WebSocket工控实时监控的几个关键技术需求低延迟信号值变化应在 200ms 内反映到前端服务端主动推送而非前端轮询双向通信前端需要发送分页、搜索、分组变更参数HTTP 长轮询Long Polling和 SSEServer-Sent Events在某些场景可以代替 WebSocket但双向通信和后端负载均衡的支持让 WebSocket 成为工业 Web 监控最广泛的选择。4.2 Hub Client 模型借鉴了 Gorilla WebSocket 示例中的经典模式Hub (连接管理器) ├── clients map[*Client]bool ← 所有活跃连接 ├── alarmEngine ← 告警引擎引用 ├── redis ← Redis 客户端 ├── interval / alarmInterval ← 双周期定时器 └── stopCh ← 优雅关闭信号 Client (单个连接) ├── conn *websocket.Conn ← 底层连接 ├── send chan []byte ← 带缓冲的写通道 ├── Category / Page / PageSize ← 分页参数每个连接独立 ├── Search / Group ← 搜索和分组过滤 ├── writePump() ← 独立的写协程 └── readPump() ← 独立的读协程核心设计每个连接独立维护分页状态。这意味着用户 A 在看 DI 信号的第 3 页时用户 B 在看 AI 信号的第 1 页且按上料柜筛选——两者互不干扰。readPump()接收客户端的page、search、group消息后更新对应 Client 的状态broadcast()遍历所有 Client 时各自计算分页数据。4.3 双周期推送机制这是本系统一个值得注意的设计。很多实时系统使用单一的推送周期但信号数据和告警事件的数据特征完全不同维度信号数据告警事件数据量大全量 DI/AI小状态变化的规则数时延要求高操作员看实时值中告警可以接受 1-2s 延迟产生方式定时拉取定时评估因此设计两个独立的 tickerfunc(h*Hub)run(){ticker:time.NewTicker(h.interval)// 默认 150msalarmTicker:time.NewTicker(h.alarmInterval)// 默认 2000msfor{select{case-ticker.C:h.broadcast()// 推送信号数据case-alarmTicker.C:h.broadcastAlarms()// 推送告警事件case-h.stopCh:return}}}信号推送周期可在app.json的push_interval_ms字段中配置范围限制在 50-1000ms告警推送周期通过alarm_push_interval_ms配置范围 200-60000ms。4.4 客户端协议前端通过 WebSocket 发送 JSON 格式的命令来控制后端推送行为{type:page,category:di,page:3,pageSize:24}{type:search,search:真空}{type:group,group:上料柜}后端处理逻辑在readPump()的 switch 中对于search和group类型会立即触发一次单客户端的数据推送sendPageUpdate()保证用户操作后不等待下一个 tick 就有响应。五、告警引擎原理与实现5.1 告警引擎架构告警引擎是整个系统的核心模块负责将原始信号值转化为有业务含义的告警事件。其内部结构如下typeEnginestruct{mu sync.RWMutex rules[]Rule// 编译后的规则列表prevValuesmap[string]float64// 每个信号的上周期值用于边沿检测triggeredmap[string]bool// 每个信号的当前告警状态去重关键store AlarmWriter// 持久化接口}三个核心字段表达了一个状态机rules静态的规则定义编译后prevValues动态的上次快照triggered动态的当前告警状态5.2 条件类型体系告警条件分为 DI 和 AI 两大类DI 条件边沿检测需前后值对比条件含义触发条件rising_edge上升沿old0, cur1falling_edge下降沿old1, cur0any_change任意变化old ≠ curAI 条件当前值判断条件含义触发条件gt大于cur thresholdgte大于等于cur ≥ thresholdlt小于cur thresholdlte小于等于cur ≤ thresholdeq等于cur thresholdne不等于cur ≠ thresholdrange区间cur ∈ [min, max]5.3 核心去重算法这是引擎最核心的设计。如果不做去重一个条件满足的信号会在每个评估周期2s不断产生告警事件导致前端告警日志被刷屏、操作员无法关注到真正的新增告警。func(e*Engine)Evaluate(valuesmap[string]float64)[]AlarmEvent{// ... 遍历所有规则 ...wasTriggered:e.triggered[key]// 上次是否触发iftriggeredwasTriggered{// 状态未变化 → 跳过continue}e.triggered[key]triggered// 记录新状态// 生成事件 ...}去重效果假设某真空压力信号 AI 规则gt 0.8当压力从 0.5 升到 0.9首次超阈值triggered从 false → true产生告警激活事件后续周期持续 0.9triggered始终为 true不产生事件压力回落到 0.7triggered从 true → false产生告警恢复事件这种状态机模型产生的告警事件天然是一对一的激活/恢复配对便于前端展示为清晰的时间线。5.4 DI 边沿检测的容器安全DI 信号的prevValues默认值为 0Go 的零值这意味着第一个评估周期会将 old0 作为前值。对于初次启动时已经为 1 的信号若规则配置了rising_edge0→1 上升沿会不会误触发答案是不会。Engine.ResetPrevValues()在启动时被调用将当前读取到的所有信号值初始化到prevValues中从而避免冷启动误报func(h*Hub)broadcastAlarms(){// ... 获取 values ...floatVals:extractFloatValues(values)h.alarmEngine.ResetPrevValues(floatVals)// 首次时同步前值events:h.alarmEngine.Evaluate(floatVals)}5.5 热更新机制工业生产环境不允许频繁重启服务。规则热更新的实现路径前端 POST /api/rules → handleRulesCreate()→ 更新 globalAppCfg.Rules(内存)→ config.SaveAppConfig()(持久化到 app.json)→ hub.ReloadRules()(热更新引擎)→ engine.ReloadRules()→ 重新编译所有规则 → 重置 triggered 状态 → 新的规则集开始工作注意ReloadRules会重置triggered状态这是合理的——旧规则的告警状态不应影响新规则的首次评估。5.6 告警历史存储SQLite告警历史采用 SQLite 持久化选用 SQLite 而非 MySQL/PostgreSQL 有明确的工程考量零运维— 无需安装数据库服务modernc.org/sqlite是纯 Go 实现的嵌入式 SQLite编译后单一二进制WAL 模式— 启用PRAGMA journal_modeWAL支持并发读/写索引覆盖— 对signal_key、time、level分别建立索引覆盖主要查询场景历史查询 API 支持多条件筛选和分页SELECT*FROMalarm_historyWHEREsignal_key?ANDlevel?ANDactive?ORDERBYidDESCLIMIT?OFFSET?六、前端架构6.1 零框架单页应用前端采用纯原生技术栈——HTML5 CSS3 Vanilla JavaScript。在 React/Vue 主导的前端生态中这种选择看似落后但在工控场景中有其合理性交付即运行没有 npm install、没有构建步骤go build后二进制内置 web 目录离线可用前端逻辑简单且确定性强不需要框架的响应式系统低资源占用工业现场的前端往往运行在老旧工控机上无框架意味着更少的内存和 CPU 消耗8.2 模块设计前端代码按功能拆分为清晰的模块均在 app.js 中模块职责关键函数WebSocket 连接连接管理、心跳、重连connectWebSocket()信号渲染卡片生成、状态更新renderSignals(),updateSignals()分页控制页码、页面大小、跳转updateControls()搜索与分组关键字过滤、设备分组handleSearch(),handleGroup()告警面板实时告警滚动、未读计数addAlarm(),updateBadge()告警历史分页查询、筛选loadHistory()规则管理表单 CRUD、导入/导出loadRules(),submitRule(),deleteRule()6.2 WebSocket 重连策略工业现场网络波动频繁前端实现了断线自动重连间隔从 1s 指数退避到 30sfunctionconnectWebSocket(){wsnewWebSocket(ws://${location.host}/ws);ws.onclose(){statusDot.classNamestatus-dot disconnected;statusText.textContent已断开;setTimeout(connectWebSocket,Math.min(reconnectDelay*2,30000));// 指数退避};}6.3 信号卡片渲染每个信号点渲染为一个卡片DI 和 AI 的展示形式不同DI 卡片以圆形指示灯表示状态绿1/ON灰0/OFF点击可查看最近变化时间AI 卡片显示实时数值和单位背景色按数值范围渐变正常白底异常红底/黄底卡片通过 CSS 过渡动画实现数值变化时的闪烁效果让操作员在余光范围内也能感知信号变化。七、REST API 设计7.1 API 概览方法路径说明GET/api/signals获取所有 DI/AI 信号供下拉选择GET/api/rules获取所有告警规则POST/api/rules新增/更新告警规则DELETE/api/rules?signalX删除指定信号的规则GET/api/rules/export导出全部规则JSON 下载POST/api/rules/import导入规则JSON 上传覆盖式GET/api/alarms查询告警历史分页、筛选GET/api/groups获取信号分组列表7.2 规则导入/导出实现规则导入导出是为了满足工控现场常见的场景新产线调试时需要在同类设备间复制规则配置。导出直接序列化globalAppCfg.Rules为 JSON设置Content-Disposition: attachment触发浏览器下载。导入接收上传的 JSON 文件覆盖写入当前配置文件和引擎内存。覆盖策略比合并策略更适合工控场景——操作员需要的是精确还原而非复杂的 diff/merge。7.3 规则状态管理规则每条告警规则由signal唯一标识因此 POST 操作实际是一个 upsert存在即更新不存在即新增idx:-1fori,r:rangeglobalAppCfg.Rules{ifr.SignalKeyrule.SignalKey{idxibreak}}ifidx0{globalAppCfg.Rules[idx]rule// 更新}else{globalAppCfg.Rulesappend(globalAppCfg.Rules,rule)// 新增}这样设计的原因一个信号点只能有一条告警规则——你无法同时对一个真空压力定义大于 0.8 告警和大于 0.9 告警这是逻辑矛盾。如果确实需要多条规则应该定义不同的信号 Key。八、关键设计决策与技术细节8.1 Redis MGET vs. 逐 Key 读取信号数量在几百到上千级别时逐 Key GET 的网络开销不可忽略。MGET 一次性批量读取所有 Key将 N 次网络往返RTT压缩为 1 次。func(c*Client)BatchFetchValues(keys[]string)map[string]interface{}{vals,err:c.client.MGet(c.ctx,keys...).Result()// keys[i] → vals[i] 一一对应}隐含的风险当某个 Key 不存在时MGET 返回的对应位置为 nil代码中通过vals[i] nil判断并赋默认值 0避免空指针。8.2 WebSocket 写缓冲与背压每个 Client 的send通道容量为 256 条消息。当某个客户端网络缓慢导致消息堆积时select{caseclient.send-data:default:// 缓冲区满跳过该客户端}背压策略慢客户端被优雅降级——跳过推送而非阻塞主循环。如果网络一直不通writePump()的SetWriteDeadline(10s)会超时关闭连接释放资源。8.3 告警消息模板与格式化规则配置中的message字段支持{value}模板变量在FormatMessage中被替换为当前值funcFormatMessage(templatestring,curValfloat64)string{returnfmt.Sprintf(template,curVal)}目前预留了接口实际代码中通过strings.Replace实现了{value}替换。设计上未来可以扩展更多变量如{threshold}、{signal_name}。8.4 双配置文件路径通过环境变量覆盖所有配置路径均可通过环境变量覆盖适配容器化部署场景ioCfgPath:config/ioboard/ioconfig.jsonifp:os.Getenv(IO_CONFIG_PATH);p!{ioCfgPathp}同理APP_CONFIG_PATH和ALARM_DB_PATH也支持环境变量覆盖。8.5 嵌入静态资源Go 1.16 引入的//go:embed指令将 web 目录编译进二进制//go:embed web/*varwebFS embed.FS输出仅一个io-monitor.exe文件部署时无需拷贝 HTML/CSS/JS 文件消除了分发时的路径依赖问题。九、构建与部署9.1 构建go build-oio-monitor.exe.编译产物为单二进制文件约 20MB含 Web 静态资源和 SQLite 引擎。9.2 运行# 基本运行使用默认配置路径io-monitor.exe9.3 配置文件清单io-monitor/ ├── io-monitor.exe # 编译后的可执行文件 ├── config/ │ ├── app.json # 应用配置Redis、端口、规则、分组 │ └── io/ │ └── io.json # IO 信号定义 └── data/ └── alarms.db # SQLite 数据库自动创建十、故障排查现象常见原因检查项前端显示正在连接…Redis 不可用config/app.json中的 Redis 地址/密码是否正确Redis 服务是否运行信号值全为 0Redis 中无对应 Key检查第三方程序是否在写入 Redis用redis-cli手动 MGET 验证告警引擎不触发规则配置错误检查 rule 的 signal 是否在 ioconfig.json 中存在条件类型是否正确导入规则无响应文件格式错误确认上传文件为合法 JSON 数组确认文件扩展名为.json导出文件为空无规则数据规则管理面板中是否有已配置的规则十一、扩展性设计本系统在设计之初就考虑到未来可能的功能扩展多协议数据源— 当前的 Redis 层可抽象为DataSource接口未来可接入 Modbus TCP、OPC UA、MQTT 等告警通知渠道—AlarmWriter接口目前写入 SQLite可实现同样的接口写入钉钉/企业微信/邮件信号历史曲线— 前端的 WebSocket 协议已预留 Category 扩展字段可新增趋势图数据包类型多级用户权限— 鉴权逻辑可在 HTTP 中间件层注入不侵入业务代码十二、快速开始环境要求Go 1.26Redis信号数据源支持 WebSocket 的现代浏览器构建gitclonerepo-urlio-monitorcdio-monitor go build-oio-monitor.exe.配置编辑config/app.json{redis:{addr:192.168.1.100:6379,password:,db:0},server:{port:8080,push_interval_ms:150,alarm_push_interval_ms:2000},signal_groups:[{name:上料柜,keys:[di_load_cab_*,ai_pc_table_*]}],rules:[{signal:di_load_close_detection,condition:rising_edge,level:warning,message:上料柜门1闭合(0→1 上升沿)}]}信号定义文件config/io/io.json包含 DI/AI/AO/DO 的 Key、名称、地址等硬件映射信息。运行# 默认路径io-monitor.exe# 自定义配置路径IO_CONFIG_PATHconfig/io/io.jsonAPP_CONFIG_PATHconfig/app.json io-monitor.exe# 自定义 SQLite 告警数据库路径ALARM_DB_PATHdata/alarms.db io-monitor.exe访问浏览器打开http://localhost:8080项目结构io-monitor/ ├── main.go # 程序入口 HTTP 路由 REST API ├── go.mod / go.sum # Go 模块依赖 │ ├── config/ │ ├── app.json # 应用配置 (Redis、Server、Rules、SignalGroups) │ └── io/ │ └── io.json # IO 信号定义 (DI/AI/DO/AO) │ ├── internal/ │ ├── config/ │ │ └── config.go # 配置类型定义 加载/保存 │ │ │ ├── redis/ │ │ └── redis.go # Redis 客户端 (批量 MGET) │ │ │ ├── alarm/ │ │ ├── types.go # 告警类型定义 │ │ ├── rule.go # 规则编译 条件评估函数 │ │ ├── engine.go # 告警引擎 (状态跟踪 去重) │ │ └── history.go # SQLite 告警历史存储 │ │ │ └── ws/ │ └── hub.go # WebSocket Hub 数据推送 分页 │ ├── data/ │ └── alarms.db # SQLite 告警数据库 (运行时自动创建) │ └── web/ ├── index.html # 主页面 ├── style.css # 样式表 └── app.js # 前端应用逻辑web 目录通过//go:embed web/*嵌入二进制中部署时无需携带静态文件。REST API信号列表GET /api/signals返回所有 DI 和 AI 信号的 key/名称/类型供规则管理下拉选择。规则 CRUDGET /api/rules → 获取所有规则 POST /api/rules → 新增或更新规则 DELETE /api/rules?signalX → 删除指定信号的规则规则导入/导出GET /api/rules/export → 导出全部规则为 JSON 文件下载 POST /api/rules/import → 导入 JSON 文件中的规则覆盖式告警历史GET /api/alarms?page1pageSize20levelwarningsignalXactive1信号分组GET /api/groups → 获取配置的信号分组列表前端界面功能说明信号看板按分页展示 DI/AI 信号卡片实时更新数值和单位Tab 切换DI数字信号/ AI模拟信号分类显示趋势曲线点击信号卡片趋势按钮弹窗显示历史折线图AI 蓝色平滑曲线、DI 绿色步进波形分组过滤按区域上料柜、分拣区等快速筛选关键字搜索输入信号名称或 Key 即时过滤分页控制首/末/上下页导航自定义每页数量信号关注点击 ★ 关注信号切换仅显示关注模式列表自动保存至浏览器告警日志实时推送告警未读计数徽标支持清空告警历史按级别/信号/状态筛选支持分页查询规则管理可视化配置告警规则增/删/改热更新生效规则导入/导出JSON 格式批量导入导出方便备份和迁移技术栈层技术后端Go 1.26 - 标准库net/http、encoding/json、embed数据源Redis -go-redis/redis/v8实时推送WebSocket -gorilla/websocket历史存储SQLite -modernc.org/sqlite前端原生 HTML CSS JavaScript无框架依赖十三、总结本文从原理、架构、实现三个层面详细阐述了 IO 信号监控平台的设计思路和工程实现。回顾整个系统的构建过程有几点体会值得记录第一工控软件选型要务实。Go 语言的并发模型天然适合多连接场景每个 WebSocket Client 一个 goroutine编译为单二进制部署极大简化了现场交付。SQLite 在告警历史存储这类低频写入场景中表现稳定零运维的特性在工控现场尤为宝贵。前端选择无框架原生栈避免了版本锁定和构建工具链的维护成本。第二去重即降噪。告警引擎的状态机去重算法是整个系统中最小的代码片段仅 5 行却带来了最大的体验改善——从每 2 秒刷屏一次到仅状态切换时通知这就是所谓少即是多在工控软件中的体现。第三配置文件是隐形的 API。双文件配置io.json app.json的设计体现了关注点分离的原则。生产实践中信号定义由设备工程师维护告警规则由工艺工程师配置各自在擅长的层面操作互不干扰。第四监控系统的价值不在数据而在信息。原始信号值只是数据经过规则引擎转化为告警事件才成为信息。而告警去重、分组过滤、历史追溯这些机制则是将信息转化为可执行决策的关键。希望本文能对从事工控软件开发、设备数据采集、智能制造方向的同行有所启发。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…