简介:这是一套面向计算机专业本科生及实训学员的智慧农业平台毕设级完整工程,聚焦农业物联网系统开发实践,解决设备接入、农事调度与可视化溯源三大核心问题,适用于毕业设计、课程设计、大创项目及工程实训等场景。资源包共1603个文件,含592个Java后端服务代码、221个Vue前端页面组件、224个SVG图标资源、163个JS交互逻辑及配套SQL、配置文件与构建脚本,整体300.72MB,结构清晰,模块划分明确,涵盖权限管理、物模型定义、设备协议适配(MQTT/TCP/Modbus/RS485/BG28181摄像头)等工业级能力。已有147人学习下载,项目经实测可直接运行,答辩平均分96分,附带完整源码、工程文件与说明文档,支持快速复现;同时提供系统开发经验支持与延伸资料协助,助力从学习理解到项目落地的全过程。
1. 青蛙智慧农业平台不是“演示系统”,而是可部署、可调试、可扩展的全栈农业物联网工程实践
很多同学拿到毕设资源第一反应是“能跑就行”,结果在答辩前两天发现设备接入失败、大屏数据不刷新、溯源链路断在MQTT订阅环节——青蛙智慧农业平台恰恰反其道而行:它把毕业设计里最容易被忽略的生产级工程约束全部显性化。这不是一个前端页面+模拟数据的PPT式项目,而是真实覆盖设备层(BG28181摄像头、Modbus温湿度传感器)、协议层(MQTT/TCP/RS485双模适配)、服务层(EMQX Web Hook联动权限校验)、展示层(Nginx反向代理+Bootstrap响应式大屏)的闭环系统。它解决的是农业物联网落地中最痛的三个断点:异构设备协议无法统一纳管、农事任务与设备状态脱节、溯源信息缺乏实时设备证据链。适合需要交付可运行系统、接受现场调试、且需体现工程规范性的本科毕设、高职实训及企业级轻量农业IoT原型验证场景。
2. 设备接入模块深度解析:从BG28181视频流到Modbus传感器数据的协议桥接实现
2.1 协议适配层设计逻辑:为什么必须用EMQX+Web Hook而非直连MySQL?
青蛙平台设备接入模块的核心矛盾在于:农业现场设备协议碎片化(GB28181视频流、Modbus RTU传感器、TCP自定义指令)与后端统一数据模型之间的鸿沟。若采用传统方案——每个协议写独立服务直连数据库——将导致三类问题:设备上线时需重启服务、告警规则无法跨协议复用、溯源时间戳精度受服务调度影响。平台选择EMQX作为消息中枢,关键在于其支持协议插件热加载与Web Hook事件驱动。emqx_web_hook.conf中配置的http://localhost:8080/api/v1/device/event端点,实际承接了所有设备连接/断开/消息到达事件,由Spring Boot服务完成协议解析与物模型映射。这种解耦使新增RS485设备仅需修改emqx_auth_http.conf中的认证URL参数,无需触碰EMQX核心配置。
提示:
emqx_auth_http.conf中auth.http.auth_req字段指向的HTTP接口,必须返回JSON格式的{ "result": "ok", "username": "dev_001", "password": "xxx" },否则设备会被EMQX拒绝接入。该接口在源码DeviceAuthController.java中实现,需确保MySQL中device_info表存在对应设备记录。
2.2 BG28181摄像头接入实操:SIP注册与媒体流拉取的关键参数
平台对GB28181设备的支持并非仅停留在“能连上”,而是实现了国标要求的完整信令流程。package.bat打包时嵌入的gb28181-sip-server.jar负责SIP注册管理,其核心配置在application.yml中:
gb28181: server: ip: 192.168.1.100 # 服务器公网IP,非localhost port: 5060 device: expires: 3600 # 注册有效期,单位秒 heartbeat: 30 # 心跳间隔,必须≤expires/2设备注册成功后,前端调用/api/v1/camera/play?deviceId=DEV001触发流媒体拉取。此时nginx.conf中关键配置生效:
location /stream/ { proxy_pass http://127.0.0.1:8080/stream/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 关键:透传WebSocket Upgrade头,否则HLS播放失败 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }2.2.1 调试技巧:验证SIP注册状态的三步法
- 检查EMQX Dashboard:访问
http://localhost:18083→ “Clients”页签,筛选Client ID含GB28181_前缀的连接,确认State为connected - 抓包验证SIP信令:在Wireshark中过滤
sip && ip.addr==192.168.1.100,观察REGISTER响应码是否为200 OK - 验证流地址可用性:直接浏览器访问
http://localhost/stream/DEV001/hls.m3u8,返回HTTP 200且内容为M3U8索引文件即成功
2.3 Modbus/TCP设备接入:寄存器映射与JSON Schema生成
平台通过modbus-tcp-client.jar实现工业协议解析,其核心在于modbus_mapping.json配置文件。以温湿度传感器为例,该文件定义:
{ "deviceType": "TEMP_HUMI", "registers": [ { "address": 0, "length": 2, "dataType": "float32", "field": "temperature", "scale": 0.01 }, { "address": 2, "length": 2, "dataType": "float32", "field": "humidity", "scale": 0.01 } ] }当设备上报原始字节[0x42C80000, 0x42F00000]时,服务端按float32解析得25.0和48.0,再乘以scale得到最终值。此配置被DeviceDataParser.java动态加载,避免硬编码导致的协议变更风险。
| 参数 | 说明 | 常见错误 |
|---|---|---|
address | Modbus寄存器起始地址(0-indexed) | 误填为1-indexed导致数据错位 |
dataType | 支持int16/uint16/float32/string | float32需占用2个寄存器,长度必须为2 |
scale | 数值缩放系数,用于处理小数精度 | 温度传感器常为0.01,湿度常为0.1 |
3. 农事任务管理模块:基于RBAC权限模型的任务派发与设备联动机制
3.1 权限管理实现:Spring Security + 自定义FilterChain的细粒度控制
平台未采用Shiro等传统框架,而是基于Spring Security 5.7构建三层权限体系:
- 系统级:管理员可操作所有菜单(
ROLE_ADMIN) - 区域级:农场主仅能管理所属地块设备(
ROLE_FARMER,权限表达式hasRole('FARMER') and #deviceId.startsWith('AREA001_')) - 设备级:技术员仅能查看指定设备告警(
ROLE_TECHNICIAN,通过@PreAuthorize("@deviceService.canAccess(#deviceId, principal.username)")注解校验)
关键配置在SecurityConfig.java中:
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/api/v1/admin/**").hasRole("ADMIN") .antMatchers("/api/v1/farm/**").access("hasRole('FARMER') or hasRole('ADMIN')") .antMatchers("/api/v1/device/**").authenticated() .and() .csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); }注意:
build.bat编译时会将mysql.cnf中的数据库密码注入application-prod.yml,若本地MySQL密码非root123,需手动修改mysql.cnf第3行password=root123并重新执行build.bat。
3.2 农事任务与设备状态的双向绑定
农事任务(如“灌溉3号大棚”)的执行依赖设备状态反馈,平台通过任务状态机+设备事件监听实现闭环。当用户提交任务时,系统执行:
- 校验任务关联设备是否在线(查询EMQX Clients API)
- 向设备Topic
cmd/irrigation/3发布JSON指令{"action":"start","duration":1800} - 启动定时任务监听
event/irrigation/3/status主题,超时未收到{"status":"success"}则标记任务失败
该逻辑在TaskExecutionService.java中实现,其中设备指令发布使用EMQX REST API:
curl -X POST http://127.0.0.1:8080/api/v1/mqtt/publish \ -H "Content-Type: application/json" \ -d '{ "topic": "cmd/irrigation/3", "qos": 1, "payload": "{\"action\":\"start\",\"duration\":1800}", "retain": false }'3.2.1 任务失败自动降级策略
当设备离线或指令超时,系统触发降级流程:
- 向管理员推送企业微信告警(调用
wechat-alert.jar) - 将任务状态置为
WAITING_RETRY,按指数退避重试(首次1分钟,二次2分钟,三次4分钟) - 第三次失败后生成工单至
task_ticket表,供人工介入
此机制在TaskRetryScheduler.java中实现,避免因网络抖动导致农事中断。
4. 智慧农业大屏与溯源系统:实时数据渲染与区块链存证的轻量级实现
4.1 大屏数据实时推送:WebSocket + Redis Pub/Sub双通道保障
大屏前端(index.html)通过WebSocket连接/ws/dashboard获取实时数据,后端采用Redis Pub/Sub解耦数据源与推送逻辑:
// DeviceDataReceiver.java监听MQTT消息 @EventListener public void onMessageArrived(MqttMessageEvent event) { String payload = new String(event.getMessage().getPayload()); // 解析后存入Redis Hash结构 redisTemplate.opsForHash().put("dashboard:data", event.getTopic(), payload); // 同时发布到Pub/Sub频道 redisTemplate.convertAndSend("channel:dashboard", payload); } // WebSocketHandler.java订阅Redis频道 @PostConstruct public void init() { redisMessageListenerContainer.addMessageListener( (message, pattern) -> { simpMessagingTemplate.convertAndSend("/topic/dashboard", message.getBody()); }, new PatternTopic("channel:dashboard") ); }此设计确保:当大屏WebSocket连接断开时,Redis Hash中缓存最新数据;重连后立即推送Hash全量数据,避免画面空白。
4.2 溯源信息生成:设备原始数据哈希上链的轻量级方案
平台未引入完整区块链节点,而是采用设备数据哈希+时间戳签名的轻量存证。当温湿度传感器上报数据时,DeviceDataProcessor.java执行:
public String generateTraceCode(String deviceId, String rawData, long timestamp) { String content = String.format("%s|%s|%d", deviceId, rawData, timestamp); // 使用SHA-256生成摘要 String hash = DigestUtils.sha256Hex(content); // 签名:用私钥对hash加密(私钥存储于conf/keystore.p12) byte[] signature = signWithPrivateKey(hash.getBytes(), "keystore.p12", "123456"); return Base64.getEncoder().encodeToString(signature); }生成的traceCode存入trace_record表,并同步写入/data/trace/目录下的JSON文件,供扫码溯源小程序读取。该方案满足《农产品质量安全追溯管理办法》对“不可篡改、可验证”的基本要求,且无额外运维成本。
| 溯源字段 | 数据来源 | 更新频率 |
|---|---|---|
| 设备ID | MQTT Topic解析 | 实时 |
| 采集时间 | 设备本地时钟(需NTP校准) | 每5分钟 |
| 环境数据 | Modbus寄存器解析值 | 同采集频率 |
| traceCode | SHA-256+RSA签名 | 每次上报生成 |
4.3 大屏适配技巧:Bootstrap栅格系统在农业场景的特殊优化
农业大屏常需在1920×1080分辨率下同时显示16路视频流+环境数据图表,标准Bootstrap的col-md-3会导致视频挤压变形。平台在index.css中覆盖默认样式:
.video-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; } .video-item { aspect-ratio: 16/9; /* 强制16:9比例 */ background: #000; overflow: hidden; } .video-item video { width: 100%; height: 100%; object-fit: cover; }同时禁用Bootstrap的响应式断点(<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">),确保大屏始终以100%缩放渲染,避免Chrome自动缩放导致字体模糊。
5. 本地快速部署与高频故障排查:从run-web.bat到EMQX日志分析的完整链路
5.1 一键启动脚本的隐藏依赖与环境校验
run-web.bat表面是简单启动命令,实则包含三层校验:
@echo off :: 第一层:Java版本检查 java -version | findstr "11.0" >nul || (echo ERROR: 需JDK 11! && pause && exit /b) :: 第二层:端口占用检测 netstat -ano | findstr ":8080" >nul && (echo ERROR: 8080端口被占用! && pause && exit /b) :: 第三层:MySQL连接测试 mysql -uroot -proot123 -e "SELECT 1" >nul || (echo ERROR: MySQL未启动或密码错误! && pause && exit /b) :: 启动顺序:MySQL → EMQX → Nginx → Spring Boot start /min mysqld --defaults-file=mysql.cnf timeout /t 3 >nul start /min emqx start timeout /t 5 >nul start /min nginx.exe timeout /t 2 >nul java -jar frog-agri-platform.jar --spring.profiles.active=prod若启动失败,需按此顺序逐项验证:
mysql.cnf中basedir路径是否指向实际MySQL安装目录emqx\etc\emqx.conf中node.name=emqx@127.0.0.1的IP是否与本机一致nginx.conf中proxy_pass http://127.0.0.1:8080的端口是否与Spring Boot配置匹配
5.2 EMQX连接失败的四大根因定位法
当设备显示“连接超时”,按优先级排查:
| 现象 | 检查位置 | 解决方案 |
|---|---|---|
| EMQX Dashboard无客户端 | emqx.log末尾是否有started字样 | 重装EMQX或检查emqx\bin\emqx.cmd中JAVA_HOME路径 |
客户端显示auth_failed | emqx_web_hook.conf中auth.http.auth_req返回状态码 | 用Postman测试该URL,确认返回{"result":"ok"} |
| 客户端连接后立即断开 | emqx.conf中zone.external.max_clientid_len = 128 | 将设备Client ID长度控制在128字符内 |
| 订阅Topic无消息 | emqx.conf中mqtt.max_packet_size = 1MB | 若视频流过大,需调高此值并重启EMQX |
5.3 溯源码扫码失败的终端兼容性修复
Android APK中扫码功能基于ZXing库,但部分国产手机(华为EMUI、小米MIUI)因后台限制导致相机权限失效。修复方法:
- 在
AndroidManifest.xml中添加唤醒白名单声明:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>- APK安装后手动进入手机设置→电池优化→找到本应用→选择“不优化”
- 若仍失败,在
ScanActivity.java中增加权限请求回调:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.CAMERA}, 100); } }此补丁已集成在android.apk的v2.3.1版本中,直接安装即可生效。
本文还有配套的精品资源,点击获取