从零开发智慧农场小程序:uni-app+Spring Boot+MQTT完整实战

📅 发布时间:2026/9/8 8:17:06
从零开发智慧农场小程序:uni-app+Spring Boot+MQTT完整实战 简介一份基于微信小程序平台的智慧农场完整源码面向农业企业、独立开发者和希望进入农业科技领域的程序员解决传统农场管理效率低、数据分散等问题。资源包共包含一千六百四十六个文件压缩包大小约二十八兆字节涵盖 PHP 后端接口、JS 业务逻辑、WXML 与 WXSS 小程序页面、HTML 管理后台、PNG 图标图片以及数据库配置等类型目录结构完整可直接部署或二次开发。已有四千七百二十五人学习该资源适合具备一定前端或后端基础、想快速搭建可运行农业管理系统的读者。源码涉及物联网设备数据对接、GIS 农田可视化、大数据分析与云服务集成等关键模块并包含用户权限、实时通讯与自动化部署相关代码可帮助深入理解现代农业小程序的完整技术栈。从后台接口到前端页面均有完善注释与配置说明尤其适合作为毕业设计、课程项目或企业原型参考。 三伏天中午大棚里温度已经冲到38℃卷帘机却没有自动打开。等我从管理房跑过去一垄草莓苗已经被蒸得蔫了半截。朋友站在棚里指着旁边三套不同品牌的传感器设备跟我说“数据我都能看到可它们各干各的我总不能天天盯着三个App过日子吧。”这就是我做这个智慧农场小程序完整版的起因——不是要再造一个监控平台而是把已经存在的设备、数据、订单、客户全部收拢到一个微信小程序里让农场主和大棚管理员都只用这一个入口干活。这篇文章会把项目从需求梳理、技术选型、功能开发到上线前踩过的坑完整写一遍。内容偏实战适合正在做智慧农业类小程序的人也适合想用uni-app加Spring Boot跑通一个前后端完整项目的人参考。你可以照着这套思路复刻一个版本也可以只挑其中某个模块借鉴。1. 从“凭感觉种地”到“数据决策”这个完整版小程序要解决什么1.1 农场的真实痛点不是缺硬件而是缺统一入口大部分小型农场的现状是设备装了一堆温湿度传感器、光照传感器、土壤墒情仪、水肥机、卷帘控制器每个都有自己的管理后台或App。但农忙时节没人有时间挨个打开去看。更麻烦的是这些设备之间的数据是割裂的——棚内温度异常时你没法通过同一个界面看到卷帘是不是没关、风机是不是没开。所以这个项目的第一个目标不是“炫技”而是把分散的数据源统一起来。农场主打开小程序就能看全貌当前温度、湿度、光照、土壤情况、设备在线状态全部在一个面板上。这一步做不好后面加什么都白搭。1.2 功能全景图环境监测、设备控制、认养商城一条链我梳理需求的时候把“完整版”拆成了六个模块每个模块对应一个实际农场场景功能模块核心能力解决什么问题环境监测温度、湿度、光照、土壤、CO2实时展示与历史曲线不用进棚也能知道环境变化设备控制卷帘、风机、水肥、遮阳网的远程开关环境异常时远程干预不用跑现场告警订阅阈值告警、设备掉线告警、微信订阅消息推送出问题第一时间知道认养与商城认养菜地/果树、在线下单、微信支付把采摘游客和会员变成线上客户数据报表日/周/月报表、投入品记录生产决策和成本核算有数据支撑用户与权限管理员、棚长、普通员工三种角色设备控制这种高危操作不能人人可碰这里提到的“完整版”不是通常意义上破解或会员解锁的意思而是指一套能直接上生产环境、把核心链路全部跑通的项目版本。我在做的时候默认所有模块都按真实农场运营去设计宁可后期砍功能也不在前期自欺欺人。1.3 为什么必须是小程序而不是App或网页这个项目我几乎没有纠结直接定了小程序。原因很简单智慧农场的用户分成两类一类是农场内部的管理者另一类是采摘游客、认养会员这两类人都在微信里。游客扫码就能打开认养页面不需要下载App管理员收到订阅消息推送点一下就能看到告警详情。这种触达效率网页H5和独立App都做不到。另一个原因是开发成本。小程序生态相对封闭但完善HBuilderX加uni-app的工作流也很成熟一套代码可以编译到微信小程序和H5管理后台顺手也能复用一套前端代码。对于预算有限的小型农场项目来说这是性价比最高的方案。2. 技术选型与整体架构uni-app Spring Boot MQTT的取舍过程2.1 前端框架对比选uni-app而不是原生小程序基于什么考虑小程序前端有两个主流选择微信原生小程序和uni-app。我之前做过两个原生小程序项目这次换成了uni-app主要权衡了三个维度维度uni-app微信原生小程序跨端能力一次编译到微信、支付宝、H5、App只能跑微信组件生态有uView等现成UI库大部分要手写或结合WeUI开发调试HBuilderX一体化浏览器H5也能跑微信开发者工具单点调试维护成本一套代码管多端多端就要维护多套我选uni-app的关键原因是这个项目需要一个管理端页面。农场管理者在电脑上开个浏览器就能看大屏数据如果前端用原生小程序管理后台就得另写一套Web工作量翻倍。用uni-app可以连管理后台一起搞定。2.2 设备通信链路设计HTTP管业务、MQTT管实时数据整个链路简单画一下是这样的传感器通过串口或485总线把数据传给DTU网关网关走MQTT协议上报到消息代理服务器后端服务订阅这些主题做入库和判断小程序端的业务请求走常规HTTP接口实时性要求高的数据用WebSocket推送。这里有一个非常容易踩的坑微信小程序不能直接连MQTT的1883端口因为小程序只允许走wss协议而标准MQTT是TCP协议。虽然MQTT.js在小程序里能跑但要做好适配而且需要在微信公众平台后台把socket合法域名配上否则真机上一连就断开。我实际的工程方案是后端单独开一个WebSocket服务订阅MQTT主题后把数据转推给小程序。前端只维护一个轻量级的WebSocket长连接这样既保证了实时性又避开了小程序对原生MQTT的限制。2.3 数据库表规划设备、告警、订单、认养怎么建关系数据库设计是这个项目里最不能省的一环。我用的是MySQL加RedisRedis主要存设备最新一条状态和用户登录态。核心表结构是这样的CREATE TABLE farm ( id bigint NOT NULL AUTO_INCREMENT, owner_id bigint NOT NULL COMMENT 管理员用户ID, name varchar(100) NOT NULL, address varchar(255) DEFAULT NULL, area decimal(10,2) DEFAULT NULL COMMENT 面积亩, PRIMARY KEY (id) ); CREATE TABLE device ( id bigint NOT NULL AUTO_INCREMENT, farm_id bigint NOT NULL, device_no varchar(50) NOT NULL COMMENT 设备编号, type varchar(20) NOT NULL COMMENT roll/fan/water/cover, nick_name varchar(50) DEFAULT NULL, status tinyint DEFAULT 0 COMMENT 0离线 1在线 2运行中, last_online_time datetime DEFAULT NULL, PRIMARY KEY (id) ); CREATE TABLE sensor_data ( id bigint NOT NULL AUTO_INCREMENT, device_id bigint NOT NULL, temperature decimal(5,2) DEFAULT NULL, humidity decimal(5,2) DEFAULT NULL, soil_moisture decimal(5,2) DEFAULT NULL, co2 int DEFAULT NULL, collect_time datetime NOT NULL, PRIMARY KEY (id), KEY idx_device_time (device_id, collect_time) );订单和认养的表也类似但有一个细节我要单独强调金额字段全部用整数分存储不要用decimal浮点数。微信支付以分为单位从数据库到接口一路用整数能避免很多四舍五入带来的脏数据。认养订单则要额外存一个周期字段比如认养30天到期前要触发续费提醒。3. 核心功能模块开发实录数据监测、远程控制与微信支付3.1 环境数据上报、历史曲线与告警触发机制传感器默认30秒上报一次数据服务端接收后写入sensor_data表。但小程序端不需要高频刷新我做了两层处理实时面板用WebSocket推送最新数据每5秒更新一次历史曲线走HTTP接口查询时按5分钟或1小时做聚合避免一次拉几千条原始记录把页面卡死。历史曲线我用的是ucharts在uni-app里集成方便折线图和柱状图都够用。曲线页的数据接口返回格式设计成时间戳加数值数组前端拿到直接渲染不在小程序端做额外计算。实测下来加载一个月的数据也没压力关键就是服务端要做好聚合查询。告警触发逻辑完全放在后端。每次收到上报数据先对比该设备对应的告警规则如果温度超过上限或低于下限就写一条告警记录然后调用微信订阅消息接口推送。这里有个坑微信订阅消息是一次性订阅用户每授权一次只能接收一条模板消息。刚开始我没注意连续测试几条告警后就报43101错误后来在页面里加了一个“开启告警提醒”的按钮用户进入监控页时主动引导订阅才解决。3.2 远程设备控制MQTT指令下发与防越权校验设备控制是智慧农场里安全要求最高的模块毕竟卷帘机误操作可能导致大棚被掀翻。我在控制接口上加了双重校验第一是登录态必须有效第二是当前用户角色必须是管理员或棚长普通员工只有查看权限。指令下发走的是这样的链路小程序调用后端HTTP接口后端校验权限后把指令发布到MQTT对应主题设备端订阅主题并执行动作执行完再通过状态主题回报结果。{ action: roll, command: open, operator: 20240915, timestamp: 1726387200, request_id: 8f6c2a1e3d }每个动作都带request_id方便设备执行超时后做结果核对。后端收到设备回报后才把device表的status改成“运行中”或“已关闭”。这样做的好处是即使设备没有真正执行管理端也不会误显示。防越权校验这块我吃了不少亏。最开始只校验用户登录态结果发现A农场的员工只要伪造请求体里的farmId和deviceId就能控制B农场的设备。后来统一封装了一个资源归属校验方法每个设备查出来后强制比对device.farm_id和当前用户绑定的farm_id不一致直接拒绝。3.3 认养与商城中的微信支付v3对接从下单到回调验签认养和商城模块的核心是微信支付v3。对接流程走通的话不难但每一步都有隐藏的坑。流程是这样用户在小程序选认养方案点支付后向服务端下单服务端调用微信支付的JSAPI下单接口拿到prepay_id后返回给前端前端再调wx.requestPayment拉起收银台。用户支付成功后微信服务器会向配置的notify_url发起回调服务端验签解密后更新订单状态。v3和v2最大的区别是签名和加密方式。v3用商户私钥做RSA签名回调报文里的resource部分用APIv3密钥做AES-256-GCM解密。我第一次对接时在回调里直接尝试整个报文解密结果一直报错。后来看了官方文档才发现只需要解密resource.ciphertext而且要用解密后的数据里的out_trade_no和transaction_id去更新订单。下单接口有几个参数特别容易搞错amount.total单位是分不是元payer.openid必须是用户当前小程序的openid不能拿别的端openid顶替notify_url必须是HTTPS地址而且要在公众平台配置好支付成功后的页面跳转我建议不要依赖回调的实时性而是前端在wx.requestPayment的success回调里先提示“支付成功”同时轮询一次订单状态接口。回调是异步的极端情况下可能有几秒延迟用户那边体验不能跟着延迟。4. 微信生态硬骨头导航栏适配、原生组件bug与联调排障4.1 自定义导航栏高度计算与动态标题实现农场监控首页需要把大棚编号和实时温度放在标题栏位置系统原生的导航栏做不到这种效果只能自定义导航栏。自定义最大的坑是不同机型的刘海屏差异尤其是iPhone的灵动岛和千元安卓机的状态栏高度相差很大。计算方式其实不复杂const systemInfo uni.getSystemInfoSync(); const menuRect uni.getMenuButtonBoundingClientRect(); const statusBarHeight systemInfo.statusBarHeight; const navHeight (menuRect.top - statusBarHeight) * 2 menuRect.height;导航栏总高度等于状态栏高度加菜单按钮所在区域的高度。注意menuRect要在onLoad之后获取不能在App启动时就缓存否则部分安卓机型会拿到空值。页面标题的动态更新我直接用数据驱动的方式在data里维护一个title变量切换大棚时更新标题文案自定义导航栏渲染时就绑定了这个变量。这不涉及uni.setNavigationBarTitle因为用了自定义导航栏之后原生的标题设置接口已经不管用了。4.2 iOS上video在swiper中全屏错位的完整排查链路这个bug是我开发过程中最头疼的一个。农场监控页用swiper轮播几个大棚的实景视频安卓上一切正常到了iPhone上一顿操作就出现视频画面偏移、全屏后旋转失灵的情况。排查过程是这样的先在微信开发者工具里复现完全没问题。换iPhone真机预览问题出现。我第一反应是video组件的宽高设置有问题把cssflex布局反复调整了几次没有效果。后来突然意识到小程序里的video是基于原生组件实现的层级天然高于普通组件在swiper这种滚动容器里嵌套iOS的内核处理起来本身就容易出问题。尝试了几个方案包括在全屏开始时用v-if把video移出swiper都不彻底。最终方案是把视频列表和播放页拆成两个独立页面swiper里只放视频封面图和播放按钮点击后跳转到新的播放页播放页单独渲染video组件。这样绕开了原生组件嵌套问题实测iPhone 14和15上都没有再出过全屏错位。这个经验我沉淀下来一句在iOS小程序里video组件尽量不要和scroll-view、swiper这类滚动容器做深层次嵌套能用跳页解决的不要硬在一个页面里嵌套。4.3 本地联调抓包看接口、内网穿透打通支付回调开发过程中接口联调是重头戏。小程序端的接口问题我习惯用抓包工具先定位。Burp Suite和Fiddler都行配置方式类似手机和电脑连同一个局域网手机WiFi代理指向电脑IP和监听端口再安装CA证书就能看到小程序发出的HTTPS请求。抓包主要用来看三样东西请求URL和参数、响应状态码、以及请求头里的token是否带对。我之前遇到过一个问题接口在开发者工具里调通真机上却提示401抓包一看是请求头里Authorization字段被小程序框架吞掉了因为字段名写法和规范不一致。这种问题不看实际请求包光靠猜是定位不了的。支付回调的本地联调更麻烦因为微信服务器需要一个公网HTTPS地址才能回调。我的做法是把本地开发环境跑起来再用内网穿透工具把一个本地端口映射成公网可访问的HTTPS地址然后在微信支付商户平台临时配置这个地址作为notify_url。这样支付完成后回调直接打到本地服务可以在IDE里断点调试验签和解密的逻辑效率比打印日志高得多。5. 上线前最后一道关审核合规、接口安全与性能瘦身5.1 审核雷区类目、资质和隐私协议小心支付功能被封上线前我专门把审核相关的坑梳理了一遍因为身边确实有人吃过亏。智慧农场小程序如果只是给自家农场用审核还相对简单一旦涉及农产品销售、认养收费就必须考虑支付类目和资质问题。最大的坑是主体。个人主体的小程序无法申请微信支付商户号所以不能接微信支付。我看到过不少开发者在小程序里接了非官方收款方式结果被判违规支付功能直接停用。项目里如果含认养和商城建议注册企业主体办理对应的食品经营许可或相关资质再去申请支付商户号。隐私协议这块也要提前准备。用户授权手机号、位置信息摄像头预览这些都要在小程序后台的“用户隐私保护指引”里明确声明。不声明或声明不全审核会被打回而且即使上线了用户首次调用涉及隐私的接口也可能被平台拦截。5.2 登录态与越权防护不能只验openid小程序登录我采用的是标准流程前端wx.login拿code后端把code传给微信接口换取openid然后服务端签发自己的token返回给前端。后续所有请求都在请求头带token后端用拦截器统一校验。但只做登录态校验是不够的。设备控制、订单查询这类接口必须做资源归属校验。我的统一做法是在controller层做一层“归属校验点”查出要操作的实体后强制检查它所属的farm_id和当前登录用户的farm_id是否一致不一致就抛401。服务端数据库里farm表和user表也通过owner_id和user_farm关联表建立绑定关系不在代码里散落各种游离的id。还有一个容易被忽略的点token过期时间不能设太久。农场管理员的手机如果丢失token有效期过长会有安全隐患。我设置的是7天过期同时Redis里做了服务端会话管理管理员在小程序里主动退出或管理员在后台踢人时可以直接删Redis里的会话记录。5.3 性能优化分包加载、数据聚合与推送节流小程序包体积是个硬指标微信主包不能超过2MB否则无法发布。我做了两件事主包里只放首页、登录页和公共组件认养商城、数据报表、设备管理全部放分包页面跳转用uni.navigateTo带url参数直接跳分包页面。这样主包体积控制在700KB左右加载速度明显提升。接口性能方面历史曲线接口我做了聚合逻辑。比如用户要看一天的数据服务端不是把几千条原始上报记录全返回而是按小时取平均值返回24个点要看一周的就按天聚合返回7个点。数据量再大也不会卡。WebSocket的推送频率也要节流。设备每30秒上报一次但前端页面可能同时打开好几个如果每次上报都全量推送手机功耗和流量都不友好。我在后端做了合并推送1秒内收到多条上报合并成一条批量消息推给前端前端再根据页面是否可见决定是否刷新。这个项目做完之后我最大的体会是智慧农场小程序的技术难点其实不在小程序本身而在如何把硬件数据、业务逻辑和微信生态的能力稳定地粘合在一起。传感器和控制器这边的设备选型不建议自己造轮子市面上带MQTT协议的DTU和网关已经很成熟直接集成能省掉一大半硬件的坑。小程序的适配问题只要坚持“真机调试加抓包定位”大部分都能快速解决。如果你照着这套思路做的时候遇到具体问题欢迎把报错信息和截图发出来我们逐个聊。本文还有配套的精品资源点击获取