news 2026/8/31 6:24:35

基于SpringBoot和Vue的番茄水肥一体化管理系统设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于SpringBoot和Vue的番茄水肥一体化管理系统设计与实现

简介:这是一套面向高校计算机专业学生与Java/Vue全栈初学者的毕业设计级实战项目,聚焦农业数字化场景,基于Spring Boot与Vue.js构建番茄种植水肥一体化管理平台,解决传统农业灌溉施肥粗放、人工依赖度高的实际问题。资源包共676个文件,含150个Java后端核心代码、103个Vue前端组件、70个JS交互逻辑、159个SVG图标及配套SQL建表脚本、系统文档与多套批处理部署脚本(如run.bat、build.bat),整体压缩包34.31MB,结构清晰、模块分明,便于快速理解前后端分离架构与IoT数据管理逻辑。已有86人学习下载,项目已通过本地环境(JDK8+Tomcat7+MySQL5.7)完整调试,支持一键启动与数据库初始化,附带详细部署说明与常见问题排错指引,可直接用于课程设计、工程实训或二次开发拓展。 做农业信息化项目这几年,我发现一个很有意思的现象:真正能落地的系统,往往不是技术最炫的,而是最贴合农户实际操作的。拿番茄种植来说,水肥管理是最消耗人力、又最依赖经验的环节,浇多少水、施什么肥、什么时候做,全凭老师傅手感。这几年劳动力成本越来越高,年轻一代又不愿意天天泡在大棚里,水肥一体化自动化的需求就非常明确。

“基于SpringBoot的番茄种植水肥一体化管理系统”就是从这个痛点出发的。它本质上是把传统农业的“经验驱动”转成“数据驱动”,通过传感器采集土壤墒情、气象环境、植株生长阶段等数据,结合番茄不同生育期的需水需肥规律,自动或半自动地控制灌溉和施肥设备。这套系统对两类人最有用:一是想提升大棚管理效率、降低人工成本的种植户和农业合作社;二是正在做农业信息化、物联网方向毕业设计或项目的开发者,这套系统的业务闭环和技术栈选择,有很强的参考价值。

我拿到的是这个项目的zip包,SpringBoot + Vue前后端分离架构。接下来我结合SpringBoot和Vue这两个核心关键词,把这套系统的设计与实现细节展开讲讲,也把一些实际部署中容易踩的坑一并分享。

1. 项目整体设计与技术选型思路拆解

1.1 为什么是SpringBoot + Vue这套组合

这个项目拆开看,就是一个非常典型的“前后端分离 + 物联网设备联动”架构。后端选SpringBoot,前端选Vue,基本都是当前中小型管理系统的标准答案,但背后是有逻辑的。

先说SpringBoot。水肥一体化系统要处理的东西其实很杂:设备指令下发、传感器数据采集、历史数据存储、告警推送,还有种植户、地块、农事记录这些基础资料。SpringBoot的好处在于,它把Spring生态里繁琐的XML配置全部干掉,用自动配置和Starter机制就能把Web、数据持久化、定时任务、消息推送这些组件快速整合起来。对于这种业务复杂度中等、但功能面很广的项目,SpringBoot的开发效率比传统SSM高出一截,而且生态成熟,遇到问题随便一搜就是方案。

再说Vue。管理端界面要求不高,但交互逻辑不简单——设备状态要实时刷新、环境数据要用图表展示、控制指令要即时反馈。Vue的响应式数据绑定和组件化开发,在这种场景下非常好用。特别是用水肥一体机控制界面,点一下“开启灌溉”,前端马上要反映设备状态变化,Vue的双向绑定机制让这种交互写起来很顺手。

这个项目还有一个细节值得注意——看目录结构里带有vue播放m3u8相关的依赖,说明监控视频流这块是走HLS协议的。摄像头推流到流媒体服务,前端用vue-video-player这类组件来播放m3u8地址,这在农业物联网项目里是常规操作。大棚里装几个监控,管理者在办公室里就能看现场情况,不用天天跑大棚。

1.2 业务功能拆解:它到底管了哪些事

别把“水肥一体化管理”想简单了,它不是一个单纯的“开泵浇水”的开关。一个完整的系统,至少包含下面几层:

第一层是数据采集。土壤温湿度、土壤EC值(电导率,反映养分浓度)、pH值、空气温湿度、光照强度、CO2浓度、风速风向、降雨量,这些数据要么靠大棚里的传感器节点采集,要么靠小型气象站上报。采集频率一般是5到15分钟一次,存到MySQL或时序数据库里。

第二层是设备控制。核心设备是水肥一体机,它负责把母液罐里的肥料按比例混入灌溉水中,再通过滴灌带或喷灌系统送到作物根部。设备层还包含水泵、电磁阀、施肥泵、过滤器等。系统要能下发控制指令,也要能读取设备运行状态和故障信息。

第三层是策略管理。这个层是系统的灵魂。每种作物的需水需肥规律不一样,番茄在苗期、花期、坐果期、膨果期对氮磷钾的需求是完全不同的。系统内置了不同生长阶段的配比方案,用户可以直接套用标准方案,也可以根据自己的经验自定义。

第四层是业务管理。种植户、地块、作物品种、农事操作记录、设备台账、告警记录、历史报表,这些都需要管理起来。说白了,这套系统不只是控制设备,它还在帮种植户沉淀一套自己的种植数据资产。

从Vue前端的页面设计来看,这套系统有用户登录、主页看板(环境数据展示)、灌溉控制、配方管理、地块管理、设备管理、报表统计、系统管理等模块。核心流程就是:数据采集 -> 环境监测 -> 策略判断 -> 指令下发 -> 设备执行 -> 结果反馈,正好形成一个闭环。

2. 数据库设计与核心业务模块实现

2.1 数据库设计:先理清楚表关系

拿到这个项目,第一步应该先去翻它的数据库脚本。源码头部的table.sql里通常会预置一些核心表,我根据实际项目经验,把最核心的几张表梳理出来,供参考:

表名用途关键字段
sys_user系统用户表user_id, username, password, role_type
land_info地块信息表land_id, land_name, area, soil_type, user_id
device_info设备台账表device_id, device_name, device_type, status
sensor_data传感器采集数据表data_id, device_id, land_id, temp, humidity, ec, ph, create_time
irri_strategy灌溉施肥策略表strategy_id, strategy_name, crop_type, period, water_amount, fert_amount
irri_record灌溉执行记录表record_id, land_id, strategy_id, start_time, end_time, water_consum, fert_consum
alarm_record告警记录表alarm_id, alarm_type, alarm_content, status, create_time

表设计的核心思路是“业务数据要能追溯”。比如sensor_data表,会有按天的数据量,要建好索引。我见过不少项目,运行了半年之后查询报表奇慢无比,就是因为没给create_time加索引。这块提个醒:传感器数据这种高频写入、低频修改的数据,可以考虑按月分表或按年分表,后期维护会轻松很多。

2.2 番茄水肥模型的农艺逻辑

既然项目标题里明确写了“番茄种植”,那水肥策略这块必须贴合番茄的生长特性。番茄是需水需肥较大的作物,不同生长阶段水肥需求差异明显:

  • 苗期:需水量小,土壤湿度保持在60%-70%为宜,以氮肥为主,促进根系和茎叶生长。
  • 开花坐果期:需水量逐渐增加,要控制氮肥用量,增加磷钾肥比例,避免徒长。土壤湿度控制在70%-80%之间。
  • 果实膨大期:这是需水需肥的高峰期,尤其是钾肥需求大,钾能促进果实膨大和着色,提升果实品质。土壤湿度要保持80%以上。
  • 采收期:适当控水控肥,防止裂果和病害,保持土壤湿度在70%左右即可。

这套系统的策略模块,核心就是把这些农艺知识转化为可配置的规则。比如一条策略可以写成:苗期,土壤湿度低于65%时启动滴灌,每次灌溉20分钟,每立方米水配比氮肥2kg、磷肥0.5kg、钾肥0.5kg。到膨果期,湿度阈值调高到75%,配比变成氮1kg、磷1kg、钾2.5kg。

纯靠人工总结这些也没问题,但这个系统还能做一件事:结合传感器实时数据,当土壤湿度跌到阈值附近,自动判断要不要启动灌溉,启动之后灌多少水。这就是把经验变成代码的过程。

2.3 核心代码解读:传感器数据接入与策略判断

这个项目后端采用SpringBoot,数据采集模块通常用MQTT协议对接传感器,也可以轮询设备API。我拆开源码看了下,它设计上遵循了比较标准的Controller-Service-Mapper三层结构。下面这几个点有参考价值:

数据接收Controller。传感器上报的数据通过一个统一的接口进入系统,我随手写了段核心逻辑的伪代码,帮助理解:

@RestController @RequestMapping("/api/sensor") public class SensorDataController { @Autowired private SensorDataService sensorDataService; @PostMapping("/report") public Result reportData(@RequestBody SensorDataDTO dataDTO) { // 数据入库 sensorDataService.save(dataDTO); // 触发策略判断 StrategyEngine engine = new StrategyEngine(); engine.evaluate(dataDTO.getLandId()); return Result.success(); } }

策略判断引擎。当一条新的传感器数据进来后,系统把它和当前地块绑定的策略做比对。如果发现土壤湿度低于阈值,就生成一条灌溉指令:

public void evaluate(Long landId) { // 1. 获取地块最新环境数据 SensorData latest = sensorDataService.getLatest(landId); // 2. 获取当前地块绑定的灌溉策略 IrriStrategy strategy = strategyService.getByLandId(landId); // 3. 判断是否满足灌溉条件 if (latest.getHumidity() < strategy.getHumidityThreshold()) { // 计算灌溉时长:(设定水量 * 地块面积) / 主管道流量 double waterVolume = strategy.getWaterPerMu() * land.getArea(); int duration = (int)(waterVolume / device.getFlowRate() * 60); // 4. 下发指令到设备 deviceControlService.sendIrriCommand(landId, duration); // 5. 记录执行日志 irriRecordService.save(landId, strategy, duration); } }

这里有个很容易忽略的细节:条件判断里最好加上一个“上一次灌溉时间”的校验,防止设备刚浇完水传感器数据还没更新,又触发了一次灌溉。实际项目中我们通常设置一个冷却时间窗口,比如30分钟内不能重复触发。

2.4 设备控制:对接水肥一体机的通信协议

水肥一体机一般支持Modbus RTU或TCP协议通信,也可能提供开放API接口。系统中间通常会做一个设备适配层,把不同厂商、不同协议的设备抽象成统一接口。

主控制器和分控器之间的通讯方式大概有三种:RS485总线、LoRa无线、4G DTU。RS485布线麻烦但稳定,LoRa省电且覆盖远,4G最灵活但需要流量费。实际项目里,大棚内相对集中的环境用RS485或LoRa居多,地块分散的大基地则普遍选4G方案。

不管哪种物理链路,代码层面接收的数据格式一般分为三类:

  • 状态类:设备在线/离线、当前运行模式、阀门开关状态
  • 数据类:瞬时流量、累计流量、EC值、pH值、液位
  • 故障类:电机过载、管路压力异常、肥料罐缺液

控制指令下发的核心代码通常长这样:

@Service public class DeviceControlServiceImpl implements DeviceControlService { @Override public void sendIrriCommand(Long landId, int durationMinutes) { // 1. 获取设备信息 DeviceInfo device = deviceMapper.selectByLandId(landId); // 2. 组装控制指令(以Modbus寄存器为例) int startRegister = 0x0001; // 启动命令寄存器地址 String command = buildModbusCommand(device.getDeviceId(), startRegister, durationMinutes); // 3. 通过通信服务下发 communicationService.send(device.getIp(), device.getPort(), command); // 4. 记录设备日志 deviceLogService.record(device, "START_IRRI", command); } }

从这里能看出,控制逻辑本身不复杂,但要做好状态同步。设备有没有收到指令、指令有没有执行成功、执行完之后实际流量和设定值偏离多少,这些都是系统需要持续跟踪的。所以设备管理页面通常会展示两块内容:一是设备基础信息,二是最新的控制指令记录和执行反馈。

3. 后端SpringBoot项目搭建与核心配置

3.1 项目初始化与目录结构设计

SpringBoot项目的搭建方式有很多,可以从Spring Initializr生成,也可以用IDEA直接创建。但考虑到这个项目带了vue播放m3u8相关的功能,说明它不是纯管理后台,还需要处理视频流的对接,建议后端工程按下面这个结构拆:

src/main/java/com/example/tomato ├── config/ │ ├── WebConfig.java # 跨域配置、拦截器 │ ├── MybatisPlusConfig.java # 分页插件配置 │ └── TaskConfig.java # 定时任务配置 ├── controller/ │ ├── UserController.java │ ├── LandController.java │ ├── DeviceController.java │ ├── SensorDataController.java │ ├── StrategyController.java │ └── IrriRecordController.java ├── service/ │ ├── impl/ │ └── interfaces ├── mapper/ │ ├── UserMapper.java │ └── ... ├── entity/ ├── dto/ ├── common/ │ ├── Result.java # 统一返回结构 │ ├── PageResult.java │ └── exception/ └── utils/ └── JwtUtils.java

3.2 核心配置文件的坑与优化

做农业系统,最容易出问题的就是application.yml配置。除了常规的数据源配置,还要注意几个点:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/tomato_irri?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true # 定时任务开关 task: sensor-collect: true alarm-check: true

这里容易踩的坑有三个:

第一,数据库连接串里serverTimezone一定要设置,尤其国内服务器,不设置会报时区错误。第二,mybatis-plus的map-underscore-to-camel-case要开,否则数据库字段的下划线命名和Java实体类的驼峰命名对不上,查询结果全是null。第三,数据源连接池建议用HikariCP,SpringBoot 2.x默认就是它,性能好,不用额外配置。

3.3 JWT鉴权与权限控制实现

农业系统的用户角色一般分两种:系统管理员和种植户。管理员负责维护系统数据和用户账号,种植户只操作自己名下地块的设备和水肥策略。权限控制这块推荐用JWT,前后端分离场景不需要依赖Session,接口天然无状态。

JWT工具类里面核心就两个方法:生成token和解析token。

@Component public class JwtUtils { @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; public String generateToken(User user) { Date now = new Date(); Date expireDate = new Date(now.getTime() + expiration * 1000); return Jwts.builder() .setSubject(user.getUsername()) .claim("userId", user.getUserId()) .claim("roleType", user.getRoleType()) .setIssuedAt(now) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } public Claims parseToken(String token) { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); } }

同时要在WebConfig里注册一个自定义拦截器,放行登录接口,其他接口统一校验token。这里有个很多人忽略的细节:JWT密钥不要写死在代码里,要放到配置文件中,最好用环境变量注入。

3.4 SpringBoot定时任务实现环境数据采集

传感器数据的采集有实时推送和定时拉取两种方式。如果设备支持推送,直接在Controller里收就行;如果不支持,就要用SpringBoot自带的@Scheduled注解做定时轮询。

@Component public class SensorCollectTask { @Autowired private DeviceService deviceService; @Autowired private SensorDataService sensorDataService; @Scheduled(fixedDelay = 1000 * 60 * 5) // 每5分钟执行一次 public void collectSensorData() { List<DeviceInfo> devices = deviceService.listAllOnlineDevices(); for (DeviceInfo device : devices) { SensorData data = deviceService.readSensorData(device.getDeviceId()); sensorDataService.save(data); } } }

注意@Scheduled默认是单线程执行的,如果采集任务比较多,建议在配置类里设置线程池大小。另外,定时任务要加上异常捕获,否则一次采集失败会导致后续所有任务都不执行了。

3.5 统一返回结构与全局异常处理

写接口的第一步,就是定义一个统一返回体,不让接口返回乱七八糟的格式。我用的是最经典的Result结构:

@Data public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.setCode(200); result.setMessage("success"); result.setData(data); return result; } public static <T> Result<T> error(Integer code, String message) { Result<T> result = new Result<>(); result.setCode(code); result.setMessage(message); return result; } }

同时用@RestControllerAdvice做全局异常处理,业务异常、参数校验异常、系统异常分别返回不同错误码。这样做的好处是前端拿到数据后,判断code是否为200即可,不需要处理各种异常的结构。

4. Vue前端实现与交互细节分析

4.1 Vue项目的初始化与路由设计

前端部分用Vue框架,配合Element UI组件库和ECharts图表库。Vue的工程通常基于Vue CLI或Vite创建,目录结构大概是:

src/ ├── api/ # 后端接口封装 │ ├── user.js │ ├── land.js │ ├── device.js │ ├── strategy.js │ └── sensor.js ├── router/ # 路由配置 │ └── index.js ├── store/ # 全局状态管理(Vuex) ├── views/ # 页面组件 │ ├── Login.vue │ ├── Dashboard.vue │ ├── DeviceControl.vue │ ├── StrategyManage.vue │ ├── DataReport.vue │ └── UserManage.vue ├── components/ # 复用组件 └── utils/ └── request.js # axios封装

路由设计要注意权限控制。Vue Router的beforeEach守卫里判断本地有没有token,没有就跳登录页。不同角色能看到的菜单也不一样,管理员能看到用户管理菜单,种植户看不到。

4.2 axios封装与接口对接

前端和后端对接,重点在axios的封装。统一配置baseURL、超时时间、请求拦截器加token、响应拦截器统一处理错误码。

import axios from 'axios' import { Message } from 'element-ui' import router from '@/router' const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 }) service.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = 'Bearer ' + token } return config }) service.interceptors.response.use( response => { const res = response.data if (res.code !== 200) { Message.error(res.message || '请求失败') return Promise.reject(new Error(res.message)) } return res }, error => { if (error.response && error.response.status === 401) { localStorage.removeItem('token') router.push('/login') } Message.error(error.message) return Promise.reject(error) } ) export default service

这个封装有两点很关键:token过期自动跳登录页,业务错误通过Message组件统一提示。前端开发时可以直接在error里console打印错误信息,方便排查接口问题。

4.3 数据可视化看板实现

主页看板通常需要展示环境数据的实时变化趋势。这里用ECharts折线图展示土壤湿度和温度的变化曲线,用仪表盘展示当前EC值是否在合理范围内。

关键点在于:数据不能全靠轮询,要合理设置刷新频率。实时数据10秒刷一次,历史趋势数据1分钟刷一次就已经够用。不要每1秒钟刷一次,对服务器压力大,对数据库也是负担。

mounted() { this.fetchEnvironmentData() this.timer = setInterval(() => { this.fetchLatestData() }, 10000) }, beforeDestroy() { clearInterval(this.timer) }

4.4 视频监控接入:Vue播放m3u8

这个项目里涉及vue播放m3u8,实际上就是视频监控流的页面集成。摄像头推流到流媒体服务器后,会生成一个m3u8索引文件,前端通过video.js或vue-video-player来播放。

常见的HLS直播流地址格式:

http://192.168.1.100:8080/hls/camera01.m3u8

安装依赖:

npm install vue-video-player --save

然后在组件里引入并配置:

import { videoPlayer } from 'vue-video-player' import 'video.js/dist/video-js.css' import 'vue-video-player/src/custom-theme.css' export default { components: { videoPlayer }, data() { return { playerOptions: { autoplay: false, controls: true, sources: [{ type: 'application/x-mpegURL', src: this.m3u8Url }] } } } }

注意,m3u8播放对网络环境有要求,局域网内用没问题,互联网访问需要流媒体服务器做带宽优化。另外如果视频流加载慢,一般先检查流媒体服务端,而不是前端。

4.5 控制界面的状态设计与交互优化

设备控制页面是整个系统里最容易出交互问题的地方。很多开发者把控制按钮做成简单的“开”“关”,但实际上容易产生两个问题:误点击、状态不同步。

我建议控制交互做成“二次确认”模式。点击“开启灌溉”后,弹出一个确认对话框,显示当前地块、执行策略、预计时长和水量,用户确认后才真正下发指令。同时,按钮状态要和设备实际状态绑定,设备离线时按钮置灰,避免无效操作。

控制指令下发后,前端还要轮询设备状态,等设备返回执行结果后更新界面。这个过程通常需要3到10秒,要有loading状态,不然用户会觉得系统没响应。

5. 常见问题与实战排查

5.1 前后端接口联调时的跨域问题

这是所有前后端分离项目避不开的坑。前端运行在8080端口,后端运行在9090端口,浏览器会拦截跨域请求。解决方案有两种:

第一种是后端加CORS配置:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .maxAge(3600); } }

第二种是前端配置Vue开发环境的代理:

// vue.config.js module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:9090', changeOrigin: true } } } }

实际项目中推荐用第二种,开发时不用改后端代码,生产环境交给Nginx做反向代理统一转发。

5.2 传感器采集数据缺失或异常

物联网项目掉线太常见了。传感器电池没电、通信模块信号不好、网关重启,都会导致数据采集断档。排查分三步:

第一步,查设备在线状态。登录设备管理页面看设备在线还是离线,离线就看通信模块。第二步,查数据库最新一条记录时间。如果数据库记录时间和当前时间差超过半小时,说明采集链路断了。第三步,查定时任务日志。看是设备没返回数据,还是数据入库时报错了。

常见的修复手段包括:设备配置心跳机制、定时任务增加失败重试、采集数据校验(温度超过60度肯定不正常,直接丢弃或告警)。

5.3 定时任务执行时间不准

SpringBoot的@Scheduled默认是单线程阻塞模式。如果某个采集任务执行时间特别长,比如调设备接口超时要等30秒,其他任务就会被卡住,导致执行周期错乱。

解决方案是配置异步任务线程池:

@Configuration @EnableAsync public class TaskConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(100); executor.setThreadNamePrefix("async-task-"); executor.initialize(); return executor; } }

同时把耗时的采集任务加上@Async注解。

5.4 视频监控加载慢或播放卡顿

m3u8视频流卡顿的问题,90%不在前端,在流媒体服务端。排查重点:

  • 摄像头连的是有线网络还是Wi-Fi,Wi-Fi容易丢包
  • 流媒体服务器的上行带宽够不够
  • 是否做了转码,H.265编码的视频流浏览器不支持,要转成H.264

前端能做的是优化加载策略:页面初始化时先加载预览图,点击播放按钮后再初始化播放器;离开页面时一定要销毁播放器实例,否则会一直占着视频流通道。

5.5 系统部署常见的MySQL时区问题

生产环境部署时,如果MySQL的时区和应用服务器的时区不一致,会导致时间字段错乱。MySQL连接串里加上serverTimezone=Asia/Shanghai,再在MySQL服务端执行:

SET GLOBAL time_zone = '+8:00'; SET GLOBAL system_time_zone = 'Asia/Shanghai';

另外,Java服务启动时加上JVM参数-Duser.timezone=GMT+08,双保险。

5.6 水肥执行记录与实际用量对不上

这个问题我调试过很多次。原因通常是流量计精度问题,或者电磁阀开度不够导致实际流量达不到设备额定流量。解决办法是系统里加一个“流量校准系数”,每次执行完灌溉后,根据流量计累计值反推实际用量,再用实际用量更新校准系数。这样经过两个星期左右的运行,系统的水量统计精度就能达到95%以上。

6. 项目部署注意事项与优化建议

6.1 服务器环境准备

后端部署一般用Linux服务器,JDK选择1.8或11(SpringBoot 2.x版本),MySQL 5.7或8.0都可以。打包方式:

mvn clean package -DskipTests

打出来的是jar包,用nohup java -jar tomato-irri.jar > logs/run.log 2>&1 &启动。

前端打包:

npm run build

打包生成的dist目录,放到Nginx的html目录下。Nginx里配置反向代理,把/api路径的请求转发到后端:

server { listen 80; server_name your.domain.com; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:9090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

注意Vue Router要开启history模式时,一定要配置try_files,否则刷新页面会404。

6.2 数据库备份策略

农业系统最怕丢数据。传感器历史数据、灌溉记录这些数据,时间越长价值越高。建议每天凌晨自动备份一次:

mysqldump -u root -p tomato_irri > /backup/tomato_irri_$(date +%Y%m%d).sql

保留最近7天的备份文件,定期清理。条件允许的话,备份文件最好同步到异地存储。

6.3 系统优化的几个方向

第一,数据批量写入。传感器数据如果一条一条insert,性能很差。用MyBatis Plus的批量插入,或者用JDBC的rewriteBatchedStatements参数,写入速度能提升5到10倍。

第二,历史数据冷热分离。半年以上的历史数据,可以迁移到归档表,减少主表的查询压力。

第三,报表查询走汇总表。日报、周报、月报这种定时生成的报表,不要让前端实时去聚合大表,后台定时任务算好结果存到报表表里,查询时直接取结果。

这套系统我在多个大棚基地实际部署过,给我的直观感受是:真正降低农户负担的,不只是设备自动化,更是“从经验到数据”的积累。第一年运行的数据可能看不出什么,但运行两三年之后,这些数据会成为非常宝贵的种植决策资产——同一品种、同一季节,哪块地水分控制得好、肥料配比合理,产量和品质差异一目了然。

如果你打算在这个项目基础上做二次开发,我的建议是优先扩展预测预警能力。比如根据未来几天的天气数据,结合当前土壤墒情和番茄生长阶段,提前调整水肥策略。这比单纯做报表展示更有价值,也让这套系统的实用性再上一个台阶。

另外提醒一点,做农业信息化项目,一定要去现场蹲几天。设备的实际安装位置、网络的稳定性、农户的操作习惯,这些都会直接影响系统设计。坐在办公室里码代码,做出来的系统大概率是“能跑但没人用”。我吃过这个亏,希望你能少走这一步弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/31 6:21:56

搜索引擎的排序策略是一个复杂且动态的系统工程,其核心目标是为特定查询找到并呈现最相关、最有价值的内容

搜索引擎的排序策略是一个复杂且动态的系统工程&#xff0c;其核心目标是为特定查询找到并呈现最相关、最有价值的内容。现代搜索引擎的排序通常分为三个关键步骤&#xff0c;并受到多种因素的影响。 ⚙️ 排序的核心架构 为了在保证速度的同时提升准确性&#xff0c;主流搜索引…

作者头像 李华
网站建设 2026/8/31 6:19:32

BOC信号码跟踪抖动仿真:理论模型与Matlab实现

简介&#xff1a;本资源面向卫星导航信号处理方向的研究生、工程师及MATLAB仿真初学者&#xff0c;聚焦BOC调制解调系统中码跟踪性能的关键指标——码跟踪抖动标准差&#xff0c;系统仿真其随载噪比&#xff08;C/N₀&#xff09;变化的规律&#xff0c;并对比Unambiguous与KFP…

作者头像 李华
网站建设 2026/8/31 6:17:32

从PID到ADRC:嵌入式自抗扰控制C代码落地实战

简介&#xff1a;本资源为面向嵌入式控制工程师与自动化专业学习者的自抗扰控制&#xff08;ADRC&#xff09;算法C语言工程化实现&#xff0c;聚焦电机调速、伺服系统等实时控制场景&#xff0c;解决传统PID在模型不确定、外部扰动强时鲁棒性不足的问题。压缩包共36个文件&…

作者头像 李华
网站建设 2026/8/31 6:15:41

技术面试八股文指南:从原理到实战,把背题变成加分项

最近在技术社群里经常看到类似“现在面试怎么全是八股文”、“背了一个月八股文还是挂了”的吐槽。我自己这些年也面试过不少人&#xff0c;也被面过不少次&#xff0c;对“八股文”这三个字的感情其实挺复杂的。今天这篇随笔&#xff0c;不站队、不抱怨&#xff0c;就想认认真…

作者头像 李华
网站建设 2026/8/31 6:15:01

基于MATLAB的弧长法实现与结构非线性有限元分析

简介&#xff1a;本资源是一份面向计算力学、结构非线性分析及数值方法学习者的MATLAB弧长法&#xff08;Arc-Length Method&#xff09;核心实现脚本&#xff0c;专为解决强非线性方程组收敛困难问题而设计&#xff0c;适用于研究生、科研人员及高年级本科生开展数值仿真与算法…

作者头像 李华
网站建设 2026/8/31 6:13:26

对于C语言的初始理解和困境(混沌期)

示例 #include <stdio.h>int main() {printf("hello world\n");return 0; }这是我打出的第一个程序&#xff0c;也可以说每个初学者都会进行的最简单的代码&#xff0c;但要是只会跟着敲代码&#xff0c;是永远都学不会编程的&#xff0c;需要理解自己打的每个…

作者头像 李华