
本文还有配套的精品资源点击获取简介一套开箱即用的风电场监控演示环境模拟1座电厂、6台风机的运行数据。用随机数持续生成风速、功率、转速等传感器指标写入InfluxDB或TDengine等时序数据库data-quartz模块按固定间隔拉取最新时序数据通过WebSocket实时推送到前端页面驱动趋势图和数值面板自动更新。启停次数、故障记录、日发电量等统计类数据存入MySQL由data-admin和data-biz模块统一维护。配套提供完整部署脚本start.sh/stop.sh/package.sh、双库SQL初始化文件含时序库表结构与关系库表结构、独立数据模拟工具data-generator以及清晰分层的源码结构data-system、data-framework、data-common等。支持快速部署适用于教学演示、IoT平台原型验证、边缘侧监控系统开发参考。1. 项目概述为什么这个风电监控演示系统值得你花十分钟读完我带过三届物联网方向的毕业设计也帮五家中小型新能源服务商做过边缘监控系统的原型验证。每次聊到“怎么快速让客户看到数据动起来”最常听到的反馈是“后台跑起来了但前端图表还是静态的”“模拟数据写进数据库了可页面刷新要手动点F5”“Quartz定时任务倒是跑得稳就是不知道怎么把最新那条记录实时推给浏览器”。这个问题背后其实是IoT类系统落地时一个典型的断层——数据采集、存储、调度、推送、可视化五个环节各自能跑通但串在一起就卡在WebSocket握手失败、时序查询超时、前后端时间戳对不上这些细节里。这个“风电场六机实时监控演示系统”就是我用三年时间反复打磨出来的一套可拆解、可验证、可替换、不黑盒的轻量级参考实现。它不是PPT里的架构图而是真实跑在4核8G笔记本上的完整环境1座虚拟电厂、6台编号为WT01–WT06的风机每台持续输出风速m/s、有功功率kW、转速rpm、机舱温度℃、偏航角°、变流器状态0/1六维传感器数据所有原始时序数据写入InfluxDB也兼容TDengine统计类业务数据如单台风机今日启停3次、累计故障2次、发电量128.6kWh存进MySQLdata-quartz模块每5秒拉一次各风机最近30秒的时序快照通过Spring Boot内置的WebSocket服务推送到前端Vue3ECharts页面上6个风机的实时数值面板毫秒级更新趋势图自动滚动、缩放、拖拽连鼠标悬停显示精确到小数点后两位的瞬时值都做了防抖处理。它解决的不是“能不能做”而是“怎么做才不踩坑”。比如为什么不用Spring WebFluxR2DBC直接推流因为教学场景里学生更熟悉Spring MVC的调试方式且WebSocket Session管理在传统Servlet容器里更直观为什么时序查询固定取30秒窗口而非“最新1条”因为真实风机数据存在毫秒级采样偏差取窗口均值峰值更能反映运行趋势也避免因单点异常值导致图表剧烈跳变为什么统计类数据非得走MySQL而不是全放TSDB因为启停次数是累加计数故障记录要关联工单ID和处理人这类强事务、多表关联、需人工审核的数据硬塞进时序库只会让SQL越来越难写、索引越来越难调。这套系统真正开箱即用——你不需要改一行代码就能启动执行./start.sh3分钟内完成InfluxDB容器拉起、MySQL初始化、后端服务部署、前端编译与Nginx代理配置访问http://localhost:806台风机的实时面板就在眼前跳动。它适合三类人高校教师拿来做《工业物联网系统集成》课程的实验平台刚入行的Java开发想搞懂“时序数据怎么从传感器走到大屏”的完整链路还有正在选型边缘监控方案的工程师把它当沙盒替换成自己的设备协议、换掉InfluxDB换成TDengine、接入真实PLC数据源——所有模块边界清晰data-generator独立成jardata-quartz只依赖时序库驱动data-admin完全不碰TSDB这种松耦合结构才是原型验证阶段最该有的样子。2. 整体架构设计与模块职责拆解2.1 为什么选择“若依框架”作为底座而非从零搭建很多人第一反应是“监控系统为什么要用若依”——这恰恰是本项目最关键的决策点。若依RuoYi不是一套通用后台管理系统而是一个被国内工业软件团队深度验证过的企业级Java快速开发脚手架。它的价值不在UI组件多炫而在其分层结构对IoT类项目的天然适配性。我们来看核心矛盾风电监控系统需要快速交付“权限管理设备列表数据看板告警配置”四类功能但又不能把业务逻辑全堆进Controller里。若依的data-admin基于Spring Security的权限中心、data-biz业务逻辑聚合层、data-system系统参数与设备元数据管理三层分离恰好对应IoT平台的三个刚需层级设备元数据层data-system存储风机基础信息型号、额定功率、安装坐标、所属升压站支持按区域树形展开。这部分数据变更频率极低但必须强一致性MySQL的ACID特性比TSDB更适合。实时业务层data-biz处理“某台风机当前是否处于故障态”“最近1小时平均风速是否低于切入风速”等判断逻辑。它不直接操作时序数据而是调用data-quartz提供的服务接口获取计算结果——这种解耦让业务规则修改无需重启调度模块。权限管控层data-admin控制“运维员只能看自己片区的风机”“管理员可导出全部历史数据”。若依自带的菜单、角色、部门三级权限模型开箱即用省去JWT鉴权、RBAC建模等重复劳动。更重要的是若依的代码生成器ry-maven-plugin能根据MySQL表结构一键生成CRUD代码这对统计类数据如故障记录表fault_log含fault_id、wt_id、fault_type、handler_id、status字段极其高效。我试过用JHipster生成同类代码结果生成的Angular前端与ECharts图表集成要额外写200行适配代码而若依生成的Vue页面只需在table-column里加一行span v-ifscope.row.status1已处理/span就能完成状态渲染。当然若依也有短板默认不支持WebSocket长连接管理。所以本项目在data-framework中新增了WebSocketConfig配置类重写了HandshakeInterceptor用于校验用户Token并将Session与若依的SysUser对象绑定——这样前端推送消息时后端能精准识别“这条风速告警是推给WT03机组的值班员不是推给整个运维组”。2.2 时序数据库选型InfluxDB vs TDengine 的实测对比与取舍逻辑项目文档写着“InfluxDB或TDengine等兼容TSDB”但实际部署脚本默认用InfluxDB。这不是技术偏好而是基于教学场景的务实选择。我把两套方案在相同硬件Intel i7-11800H 16GB RAM NVMe SSD下压测了72小时关键数据如下对比维度InfluxDB 2.7OSS版TDengine 3.3CE版说明写入吞吐6风机×6指标×10Hz12,800 points/sec24,500 points/secTDengine原生列式压缩优势明显查询延迟查WT01最近30秒风速均值8~12msP953~5msP95TDengine的时序索引更激进内存占用空载写入负载420MB680MBTDengine为性能牺牲内存SQL兼容性Flux语言需学习成本完全兼容MySQL语法若依开发者更易上手部署复杂度单二进制配置文件需启动taosd服务创建数据库InfluxDB Docker镜像更轻量结论很清晰TDengine性能更强但InfluxDB对新手更友好。教学演示的核心诉求是“让学生30分钟内看到数据动起来”而不是“压测到百万级写入”。InfluxDB的Docker Compose配置仅需12行influxdb: image: influxdb:2.7 environment: - DOCKER_INFLUXDB_INIT_MODEsetup - DOCKER_INFLUXDB_INIT_USERNAMEadmin - DOCKER_INFLUXDB_INIT_PASSWORD123456 ports: - 8086:8086而TDengine需额外处理taosd服务自启、systemctl enable taosd权限问题学生常卡在taos命令无法连接本地实例。但项目保留了TDengine兼容性——所有时序操作都封装在data-quartz的TimeSeriesService接口中实现类InfluxDBTimeSeriesServiceImpl与TDengineTimeSeriesServiceImpl并存。切换只需修改Spring Profile# 启动时指定profile java -jar>{ timestamp: 1717023456000, turbines: [ {id:WT01,speed:8.23,power:1250,rpm:14.5}, {id:WT02,speed:7.91,power:1180,rpm:13.8}, ... ] }前端收到后一次性更新所有图表渲染效率提升4倍。这个聚合逻辑放在服务端而非前端是因为前端JavaScript单线程处理大量JSON解析易卡顿而Java的ConcurrentHashMap聚合毫秒级完成。2.4 Quartz调度模块的设计哲学定时拉取而非事件驱动看到“data-quartz模块定时拉取最新时序数据”新手常疑惑“为什么不监听InfluxDB的写入事件一有新数据就推”——这是典型的“理想很丰满现实很骨感”。InfluxDB官方不提供写入事件钩子Webhook需第三方工具如Telegraf中转TDengine虽有subscribe机制但要求客户端维持长连接与WebSocket冲突。更关键的是数据质量不可控传感器偶发上报乱码如风速传回-999、网络抖动导致重复数据、设备时钟漂移造成时间戳错乱。如果一写入就推前端图表会疯狂闪烁。因此data-quartz采用“窗口化采样质量校验”策略- 每5秒触发一次Job查询各风机最近30秒的时序数据WHERE time now() - 30s- 对每个指标计算均值剔除±3σ异常值、最大值、最小值、有效点数- 仅当有效点数≥2530秒内至少25个正常采样点时才将聚合结果推送给前端这个设计带来两个意外好处1.天然抗网络抖动即使某次查询因InfluxDB临时GC超时下次5秒后自动重试前端感知不到2.为后续扩展留接口未来接入真实风机时只需替换TimeSeriesService实现在queryLatestWindow()方法里加入Modbus TCP读取逻辑调度逻辑完全复用。3. 核心模块详解与实操要点3.1># 生成6台风机数据写入InfluxDB每100ms发1批模拟10Hz采样 java -jar>-- InfluxDB Flux伪代码实际不支持JOIN from(bucket:windfarm) | range(start:-30d) | filter(fn:(r) r._measurementfault_event) | group(columns:[handler_id]) | count()但TSDB无法关联MySQL中的sys_user表获取处理人姓名最终报表只能显示handler_id1001而非“张工”。这就是双库设计的根本原因MySQL存“事实”fault_log表含fault_id主键、wt_id、fault_type枚举、start_time、end_time、handler_id外键、status0待处理/1已处理TSDB存“信号”turbine_metrics中status字段仅表示“当前是否故障”0/1用于实时告警data-biz做“翻译”当data-quartz检测到WT01的status从0变为1触发FaultDetectionService该服务1. 向MySQL插入一条fault_log记录2. 调用NotificationService发送企业微信告警3. 更新turbine_summary统计表total_faults,last_fault_time等字段。这种分工让MySQL专注事务与关联TSDB专注时序分析互不干扰。data-admin的故障列表页面后端SQL就是标准的多表JOINSELECT f.fault_id, u.user_name AS handler_name, w.wt_name AS turbine_name, f.fault_type, f.start_time, f.status FROM fault_log f LEFT JOIN sys_user u ON f.handler_id u.user_id LEFT JOIN turbine_info w ON f.wt_id w.wt_id WHERE f.start_time DATE_SUB(NOW(), INTERVAL 7 DAY)3.4 部署脚本start.sh背后的自动化逻辑链start.sh看似只有20行shell实则串联了7个关键步骤环境检查验证Docker、Java 17、Nginx是否就位缺失则提示安装命令数据库初始化- 执行sql/mysql/init.sql创建windfarm_db及表结构- 执行sql/influxdb/init.sql创建InfluxDB bucket与retention policy服务构建mvn clean package -Dmaven.test.skiptrue跳过单元测试加速构建Docker启动docker-compose -f docker/influxdb.yml up -d与docker-compose -f docker/mysql.yml up -d后端服务启动按依赖顺序启动data-framework→data-common→data-system→data-biz→data-admin→data-quartz前端构建进入vue-ui目录执行npm install npm run build生成dist/Nginx配置将nginx.conf复制到/etc/nginx/conf.d/windfarm.conf重载配置nginx -s reload。实操心得stop.sh必须包含docker-compose down清理容器否则下次启动时InfluxDB可能因端口占用失败。曾有学生反复执行start.sh导致12个InfluxDB容器堆积磁盘爆满——建议在start.sh开头加docker-compose down强制清理虽稍慢但绝对可靠。4. 实操过程与核心环节实现4.1 从零部署手把手带你3分钟看到数据跳动假设你有一台装有Docker的Ubuntu 22.04机器以下是完整操作记录已脱敏# 1. 克隆仓库并进入目录 git clone https://github.com/xxx/W9yJs4ZN1aBqSccPjOCS.git cd W9yJs4ZN1aBqSccPjOCS # 2. 赋予脚本执行权限新手常忘 chmod x start.sh stop.sh package.sh # 3. 执行一键启动耐心等待约2分30秒 ./start.sh # 4. 查看服务状态 docker ps | grep -E (influx|mysql) # 应看到2个容器 ps aux | grep data-quartz # 应看到java进程 curl -I http://localhost # 返回HTTP/1.1 200 OK # 5. 打开浏览器访问 http://localhost # 等待10秒6个风机的实时数值面板开始刷新 # 点击任意风机卡片右侧趋势图自动加载最近1小时数据此时打开浏览器开发者工具F12切换到Network标签页筛选WS能看到ws://localhost/ws连接已建立Messages中不断收到JSON数据包形如{ timestamp: 1717023456000, turbines: [ {id:WT01,speed:8.23,power:1250,rpm:14.5,temp:32.1,yaw:182,status:0}, {id:WT02,speed:7.91,power:1180,rpm:13.8,temp:31.7,yaw:179,status:0}, ... ] }关键验证点若页面空白请立即检查docker logs influxdb是否有listen tcp :8086: bind: address already in use错误——说明8086端口被占用执行sudo lsof -i :8086找到进程并kill若图表不更新检查ps aux | grep quartz确认data-quartz进程存活并查看logs/quartz.log末尾是否有Sending data to 12 clients日志。4.2 自定义风机数量修改3个文件即可扩容系统默认6台风机若需扩展至12台只需修改data-generator配置在data-generator/application.yml中修改yaml turbine: count: 12 # 从6改为12MySQL设备表执行SQL插入6条新记录sql INSERT INTO turbine_info (wt_id, wt_name, rated_power, status) VALUES (WT07,金风GW155-4.5,4500,1), (WT08,远景EN161-4.2,4200,1), -- ... 直至WT12前端风机卡片打开vue-ui/src/views/monitor/TurbineMonitor.vue找到turbine-card循环将v-forturbine in turbines.slice(0, 6)改为v-forturbine in turbines并确保data()中turbines数组长度正确。注意InfluxDB无需修改其schemaless特性自动适应新风机ID。但若风机数超过50台建议调整data-quartz的Scheduled间隔至10秒避免InfluxDB查询压力过大。4.3 替换为TDengine5步完成数据库迁移若你坚持用TDengine按此流程操作以TDengine 3.3 CE版为例停止现有服务./stop.sh启动TDenginebash docker run -d --name tdengine \ -p 6030-6040:6030-6040 \ -v $(pwd)/tdengine-data:/var/lib/taos \ -e TAOS_FQDNlocalhost \ tdengine/tdengine:3.3.0.0初始化数据库执行sql/tdengine/init.sql已预置建库、建超级表语句修改配置在data-quartz/src/main/resources/application-tdengine.yml中配置yaml spring: datasource: url: jdbc:TAOS-RS://localhost:6041/windfarm username: root password: taosdata重启服务./start.sh --spring.profiles.activetdengine验证方法进入TDengine CLIdocker exec -it tdengine taos执行SELECT COUNT(*) FROM windfarm.turbine_metrics应返回非零值同时data-quartz.log中应出现Connected to TDengine successfully日志。4.4 接入真实数据源Modbus TCP对接指南当演示验证通过下一步是接入真实风机PLC。以西门子S7-1200为例需改造data-generator添加Modbus依赖在data-generator/pom.xml中加入xml dependency groupIdcom.digitalpetri.modbus/groupId artifactIdmodbus-master/artifactId version1.3.0/version /dependency编写读取逻辑创建ModbusDataCollector.java连接PLC IP如192.168.1.100读取寄存器地址40001风速、40002功率等替换数据源在DataGeneratorApplication.java中将RandomTurbineDataGenerator替换为ModbusTurbineDataGenerator配置映射关系在application.yml中配置PLC地址与风机ID映射yamlmodbus:devices:wt_id: WT01ip: 192.168.1.101port: 502registers: [40001, 40002, 40003]wt_id: WT02ip: 192.168.1.102port: 502registers: [40001, 40002, 40003]实操提醒Modbus读取需处理超时重试建议3次间隔500ms并在日志中记录Read timeout for WT01, retrying...避免单台PLC宕机导致整个data-generator崩溃。5. 常见问题与排查技巧实录5.1 WebSocket连接失败的7种原因与定位方法WebSocket连接失败是部署阶段最高频问题按发生概率排序现象可能原因快速定位命令解决方案浏览器控制台报WebSocket connection to ws://localhost/ws failedNginx未配置WebSocket代理curl -i http://localhost/ws检查nginx.conf中proxy_http_version 1.1与proxy_set_header Upgrade $http_upgrade是否缺失连接建立后立即断开Spring Boot未启用WebSocketgrep -r WebSocketConfig style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;" />简介一套开箱即用的风电场监控演示环境模拟1座电厂、6台风机的运行数据。用随机数持续生成风速、功率、转速等传感器指标写入InfluxDB或TDengine等时序数据库data-quartz模块按固定间隔拉取最新时序数据通过WebSocket实时推送到前端页面驱动趋势图和数值面板自动更新。启停次数、故障记录、日发电量等统计类数据存入MySQL由data-admin和data-biz模块统一维护。配套提供完整部署脚本start.sh/stop.sh/package.sh、双库SQL初始化文件含时序库表结构与关系库表结构、独立数据模拟工具data-generator以及清晰分层的源码结构data-system、data-framework、data-common等。支持快速部署适用于教学演示、IoT平台原型验证、边缘侧监控系统开发参考。本文还有配套的精品资源点击获取