新闻详情

新闻详情

首页 / 资讯中心 / 详情

SpringBoot+Vue智慧菜园管理系统开发实战:从数据库到部署

发布时间:2026/8/31 1:32:54来源:尧图网络
SpringBoot+Vue智慧菜园管理系统开发实战:从数据库到部署
简介本资源是一套面向本科毕业设计与课程实践的智慧农业管理系统完整开发方案聚焦城市居民线上租地、种菜、农事服务等真实场景助力学生快速完成Spring BootVue全栈项目落地。资源包含649个文件涵盖291个Java后端核心逻辑、98个Vue组件页面、76个JS交互脚本、35个XML配置及2个SQL建库建表脚本辅以部署文档与多环境配置development/staging/production整体压缩包仅2.3MB轻量易导入。已有31人下载学习适用于Java Web与前端工程化初学者开箱即用提供可直接运行的前后端分离代码、MySQL数据库初始化脚本、一键打包部署批处理文件package.bat/build.bat/run-web.bat及配套Word版设计说明文档结构清晰、模块解耦便于理解菜园租赁、菜种购买、农事服务等业务闭环实现逻辑。 去年接了个挺有意思的活儿帮一位做生态农业的朋友做一个智慧菜园管理系统。要求其实不复杂就是把菜园里的地块、作物、农事任务、环境监测数据都管起来方便他远程查看和安排生产。技术栈他那边没什么历史包袱我直接就定了SpringBootVue这套经典组合数据库用MySQL前后端分离最后交付代码、数据库脚本和一套完整的部署文档。项目做完之后我把整个设计与实现过程整理了出来。这不单纯是一个课程设计级别的增删改查而是一个能真正跑起来、能在服务器上部署、能支撑日常管理的完整系统。无论你是正在做类似选题的毕业生还是想自己搭一套农业管理后台的开发者这篇文章应该都能给你一些可以直接抄作业的参考。整个系统开发加部署前后用了大概三周中间踩了不少坑尤其是在环境监测数据的采集模拟、任务提醒的定时调度、以及最后部署到Linux服务器时的各种小问题。下面我会从设计思路、数据库建模、后端核心实现、前端页面开发、部署上线这几个维度把整个项目的关键细节和实操经验都拆开来讲。1. 项目整体设计与技术选型思路1.1 为什么是SpringBootVue而不是别的方案做智慧菜园管理系统本质上是一个典型的管理信息系统核心诉求就三件事数据录入、数据展示、业务流程流转。这类系统选技术栈第一优先级不是追求新潮而是追求稳定、资料多、招人好招、出问题好排查。SpringBoot在后端生态里的地位不用多说。它帮我把Spring那一大堆XML配置全部干掉内嵌Tomcat打成一个jar包就能跑对中小型项目来说部署成本极低。而且SpringBoot的自动配置机制让MyBatis、JPA、Redis这些组件的接入变得非常简单。对于这种业务复杂度不算特别高的系统SpringBoot实际上是把“快速开发、快速交付”这件事做到了极致。前端选择Vue理由也很实际。Vue的渐进式框架特性让它成为一个非常灵活的选项从简单的页面渲染到复杂的单页应用都能胜任。配合Element UI的组件库表单、表格、弹窗、日期选择这些管理后台常见的界面元素都开箱即用不需要自己造轮子。而且Vue的响应式数据绑定机制在处理环境监测数据实时刷新、任务状态动态更新这类场景时非常顺手。提示如果你是完全没接触过SpringBoot和Vue的新手我建议先花几天把SpringBoot的自动配置原理和Vue的生命周期钩子搞明白这两个点理解透了后面写代码会顺很多。1.2 系统功能模块划分拿到需求之后我第一件事不是画页面而是梳理功能模块。智慧菜园这个场景核心业务闭环大概是这样的菜园里有多个地块每个地块种了不同的作物作物生长过程中需要定期执行浇水、施肥、除虫等农事任务同时环境中温湿度、光照、土壤湿度这些数据会影响作物生长作物成熟后需要记录收获情况。按照这个闭环系统拆成了五个核心模块地块管理维护菜园里每个地块的基本信息包括地块编号、面积、位置、土壤类型、当前状态空闲/种植中等。作物与种植管理管理作物品种信息记录每次种植的作物、种植时间、预计收获时间、生长阶段等。农事任务管理生成和执行浇水、施肥、除虫、除草等任务支持任务指派、状态跟踪和提醒。环境监测管理采集和展示温度、湿度、光照强度、土壤湿度等数据支持趋势图表分析。收获与统计管理记录每次收获的产量、品质并对周期内的收成数据和农事执行情况进行统计。这五个模块不是孤立的它们之间有明确的数据关联。地块被种植记录引用种植记录会触发农事任务环境数据需要和种植周期对应。我在设计数据库表结构的时候就是把这种关联关系通过外键和逻辑约束固化下来。1.3 前后端分离架构的实际落地前后端分离这个概念很简单但在实际操作中有些细节需要注意。我采用的是标准的分离架构后端SpringBoot提供RESTful API前端Vue开发单页应用通过Axios发起HTTP请求与后端交互前端静态资源部署到Nginx后端jar包运行在服务器上两者通过反向代理关联。前后端分离的好处是开发时可以并行前端用Mock数据先跑起来后端用Postman先测接口。但这也意味着跨域问题是绕不开的。开发环境下我用了Vue的proxyTable配置代理生产环境则由Nginx统一处理转发这样就避免了CORS的很多麻烦。另外我在设计接口的时候统一了返回格式。所有接口都返回这样一个结构{ code: 200, message: 操作成功, data: {} }统一返回格式这件事看起来简单但实际影响很大。前端不管是拿列表数据还是错误提示都可以用一套逻辑去处理不用每个接口单独做适配。我见过很多项目每个接口返回格式各写各的前端代码里全是分支判断维护起来非常痛苦。2. 数据库设计与核心表结构实现2.1 数据库建模过程数据库设计是整个系统的基础这一步如果没做好后面写代码全是坑。我在建模的时候遵循了几个原则一是按业务实体分表二是关联关系清晰三是避免冗余字段四是关键字段必须加索引。智慧菜园管理系统的核心实体有用户、地块、作物、种植记录、农事任务、环境数据、收获记录。我根据这些实体梳理出了七张核心表。用户表是最基础的表我用了sys_user这个名字。字段包括主键id、用户名、密码MD5加密存储、真实姓名、手机号、角色管理员/普通用户、创建时间、更新时间。密码加密存储这一点很重要明文存密码的项目一旦数据库泄露就是灾难。地块表garden_plot记录了菜园的基本空间单元字段包括地块编号、名称、面积亩、位置描述、土壤类型、当前状态0空闲1种植中、负责人、备注。地块编号我设计成唯一索引因为日常操作中通过编号查找地块是高频率操作。作物表crop相对简单记录了作物品种信息作物名称、品种类型、生长周期天、适宜温度、适宜湿度、注意事项等。这张表的用途是给种植记录提供基础数据避免每次种植的时候重复录入农艺参数。种植记录表planting_record是核心业务表关联了地块和作物。字段包括地块ID、作物ID、种植日期、预计收获日期、实际收获日期、生长阶段育苗期/生长期/开花结果期/成熟期、种植数量、状态等信息。这里我特意加了预计收获日期的字段后面农事任务提醒和收获提醒都要靠它。2.2 核心SQL建表语句分享下面是我实际使用的建表SQL我删掉了注释保留了核心结构。这个表结构并不是我的第一版设计而是经过了两轮调整后的结果。CREATE TABLE planting_record ( id bigint(20) NOT NULL AUTO_INCREMENT, plot_id bigint(20) NOT NULL COMMENT 地块ID, crop_id bigint(20) NOT NULL COMMENT 作物ID, plant_date date NOT NULL COMMENT 种植日期, expected_harvest_date date DEFAULT NULL COMMENT 预计收获日期, actual_harvest_date date DEFAULT NULL COMMENT 实际收获日期, growth_stage varchar(20) DEFAULT 育苗期 COMMENT 生长阶段, quantity int(11) DEFAULT 0 COMMENT 种植数量, status tinyint(1) DEFAULT 0 COMMENT 状态0种植中1已收获2已失败, create_by bigint(20) DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_plot_id (plot_id), KEY idx_crop_id (crop_id), KEY idx_expected_harvest (expected_harvest_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT种植记录表;这里我特别说明两个设计细节。第一expected_harvest_date字段我单独建了一个索引idx_expected_harvest这是因为系统里有个核心功能是根据日期扫描即将到期的种植记录生成收获提醒。没有这个索引的话数据量大了之后查询会越来越慢。第二status字段我用tinyint而不是varchar一方面省空间另一方面代码里用枚举和常量对应比字符串判断更不容易出错。农事任务表farm_task设计得相对复杂一些因为它涉及任务类型、执行状态、负责人、提醒时间。字段包括任务名称、任务类型1浇水2施肥3除虫4除草5其他、关联地块ID、关联种植记录ID、计划执行日期、实际执行日期、执行人、状态0待执行1已完成2已取消、备注。这里把关联地块和关联种植记录都存下来了因为有的任务是针对整个地块的有的是针对某一次种植的。环境数据表environment_log的设计也值得一提。因为环境监测数据是高频写入的如果每五分钟写入一条一个月就能产生上万条数据。所以在设计时我没有在环境数据表上建太多索引只保留了plot_id和record_time的联合索引。2.3 事务与数据一致性处理数据库设计不只是建表还包括数据一致性的约束。我在这套系统里设置了几条关键的事务逻辑。第一条是最核心的播种事务。当操作员在地块上执行“播种”操作时系统需要同时做三件事在地块表把状态从“空闲”改为“种植中”、插入一条种植记录、生成一条“首次浇水”的农事任务。这三步必须在一个事务里完成任何一步失败都要回滚否则就会出现地块状态和种植记录对不上的情况。第二条是收获事务。收获时要更新种植记录的状态为“已收获”、填写实际收获日期、更新地块状态为“空闲”、插入一条收获记录。同理这也是一个整体事务。在SpringBoot里我用了Transactional注解来声明这些事务。这里有一个实际工作中常见的坑在使用MyBatis-Plus的ServiceImpl时Transactional注解必须加在public方法上而且不能是this调用否则事务会失效。这是Spring的AOP代理机制决定的很多新手在这里吃过亏。3. 后端核心功能实现与代码示例3.1 SpringBoot项目结构搭建后端工程我采用的是标准的包结构分层清晰各层职责单一。我的包结构大致是这样的com.smartgarden ├── controller # 控制层接收HTTP请求 ├── service # 业务逻辑层核心业务处理 ├── mapper # 数据访问层MyBatis接口 ├── entity # 实体类对应数据库表 ├── dto # 数据传输对象接收前端参数 ├── vo # 视图对象返回前端数据 ├── config # 配置类包括CORS、MyBatisPlus、定时任务等 ├── common # 通用类包括统一返回结果、异常处理等 ├── util # 工具类 └── job # 定时任务搭建步骤其实很简单我直接在Spring Initializr上选择了Spring Web、MyBatis、MySQL Driver、Lombok这几个依赖生成基础工程后手动添加了MyBatis-Plus的依赖。MyBatis-Plus比原生MyBatis方便很多内置的BaseMapper已经提供了单表的增删改查方法省去了大量写XML的时间。3.2 登录鉴权模块实现管理系统必须要有登录鉴权我采用的是JWTJSON Web Token方案。整体流程是用户提交用户名密码后端校验通过后生成一个JWT令牌返回给前端前端把令牌存在本地之后每次请求都在Header里带上Authorization: Bearer token后端通过拦截器校验令牌有效性。JWT方案相比传统的Session方案最大的优势是服务端无状态不需要在服务器内存里维护会话信息非常适合前后端分离架构。我在实现时写了一个登录接口和一个拦截器。登录接口的核心逻辑如下PostMapping(/login) public Result login(RequestBody LoginDTO loginDTO) { // 1.根据用户名查询用户 LambdaQueryWrapperSysUser wrapper new LambdaQueryWrapper(); wrapper.eq(SysUser::getUsername, loginDTO.getUsername()); SysUser user userMapper.selectOne(wrapper); // 2.校验用户是否存在以及密码是否正确 if (user null || !user.getPassword().equals(MD5Util.encrypt(loginDTO.getPassword()))) { return Result.error(用户名或密码错误); } // 3.校验用户状态 if (user.getStatus() 0) { return Result.error(账号已被禁用); } // 4.生成JWT令牌 String token JwtUtil.createToken(user.getId(), user.getUsername()); return Result.success(token); }密码加密我用了MD5加盐的方式。这里要提醒一下虽然MD5现在已经不够安全了但对于课程设计级别的系统来说基本够用。如果是生产级别的系统建议至少使用BCrypt或SHA-256加盐。拦截器部分我写了一个JwtInterceptor继承HandlerInterceptorAdapter在preHandle方法中从请求头获取令牌解析并校验。然后注册到WebMvc配置中放行登录接口和静态资源。注意JWT令牌一定要设置过期时间。我设置的是24小时这个可以根据实际需求调整。过期的令牌会被拦截器拒绝前端检测到401状态码后引导用户重新登录。3.3 环境监测数据模拟与采集这个系统的数据来源是个关键问题。如果是真实的智慧菜园环境数据会通过物联网设备上报。但作为管理系统项目我做了两套方案一套是预留了设备数据上报的HTTP接口方便将来接入真实的传感器另一套是内置了一个定时模拟数据生成器用于演示和开发测试。数据上报接口设计为POST接口接收JSON格式的数据包含地块ID、温度、湿度、光照强度、土壤湿度、采集时间。设备端只要按这个格式上报即可。数据模拟器这部分我用的是Spring的Scheduled定时任务功能。每五分钟执行一次遍历所有状态为“种植中”的地块为每个地块生成一条模拟环境数据。为了让数据更真实我在生成时加了随机波动温度会在20到30度之间浮动湿度在40%到80%之间浮动还加了基础噪声让图表曲线看起来不是死板的直线。Component public class EnvironmentDataJob { Autowired private EnvironmentLogMapper environmentLogMapper; // 每5分钟执行一次 Scheduled(cron 0 */5 * * * ?) public void generateEnvData() { // 查询所有种植中状态的地块 ListGardenPlot plots plotMapper.selectList( new LambdaQueryWrapperGardenPlot().eq(GardenPlot::getStatus, 1)); for (GardenPlot plot : plots) { EnvironmentLog log new EnvironmentLog(); log.setPlotId(plot.getId()); log.setTemperature(generateRandom(18, 32)); log.setHumidity(generateRandom(40, 85)); log.setLightIntensity(generateRandom(2000, 8000)); log.setSoilMoisture(generateRandom(20, 60)); log.setRecordTime(new Date()); environmentLogMapper.insert(log); } } }定时任务在配置类上需要加EnableScheduling注解才能生效。这个我在开发过程中踩过一次坑老是发现定时任务不执行一查才发现忘了加启动注解。3.4 农事任务管理与定时提醒农事任务管理的核心是当一条种植记录创建时系统自动生成该作物在整个生长周期内的常规农事任务。比如种一批西红柿系统会根据作物表中预设的任务模板自动生成种植后的第0天“首次浇水”、第7天“第一次施肥”、第15天“除虫”等任务。这个功能的实现思路是在crop表中增加一个task_template字段用JSON格式存储预设的任务模板如下所示[ {day: 0, type: 浇水, name: 首次浇水}, {day: 7, type: 施肥, name: 第一次施肥}, {day: 15, type: 除虫, name: 预防除虫}, {day: 30, type: 施肥, name: 第二次施肥} ]当种植记录创建时后端解析这个JSON模板逐条生成农事任务计划执行日期就是“种植日期 天数”。这样一来每种作物的种植流程都被标准化了不会出现漏掉某个重要农事环节的情况。定时提醒则是一个每天凌晨执行的定时任务扫描未来三天内需要执行的农事任务生成提醒通知。4. 前端页面开发与核心组件实现4.1 Vue项目初始化和环境配置前端工程我用的Vue CLI创建选择了Vue 2.x版本配Element UI组件库。虽然Vue 3已经出来很久了但在我做这个项目的时候Vue 2的生态最成熟Element UI稳定网上资料多遇到问题好查。如果你现在开始做也可以考虑Vue 3 Element Plus的组合其实大体的开发思路是一致的。创建完工程后第一步是配置开发环境的代理解决跨域问题。在vue.config.js中配置devServer的proxymodule.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: } } } } };这样配置之后前端页面里发请求只需要写/api/login这样的相对路径开发环境下会自动转发到后端的http://localhost:8080/login既解决了跨域问题又不用在代码里写死后端地址。以后部署到不同环境也方便只要修改代理配置就行。4.2 登录页面与路由权限控制登录页面算是系统的门面我用了Element UI的Form表单组件加了基本的非空校验。前端拿到JWT令牌后存到localStorage里。这里不建议存到sessionStorage因为用户刷新页面后sessionStorage会清空导致被踢出登录状态体验不好。路由权限控制是前端一个容易忽略但又很重要的环节。我在router配置里给每个路由的meta字段加了requiresAuth: true然后在main.js里通过router.beforeEach注册全局前置守卫router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (to.meta.requiresAuth !token) { next(/login); } else { next(); } });这段代码的意思是访问需要登录的页面时检查本地有没有令牌没有的话就强制跳转到登录页。同时我还区分了管理员和普通用户两种角色管理员能看到用户管理页面普通用户看不到。这个是配合后端的接口权限一起做的双重保障。4.3 地块管理页面的表格操作实战地块管理页面是最典型的CRUD页面也是这套系统里使用频率最高的界面。我使用Element UI的el-table组件展示地块列表el-dialog实现新增和编辑弹窗el-form承载表单。这里我分享一个开发经验前端表格里展示的都是后端返回的原始字段值比如状态字段显示的是0或1但用户希望看到的是“空闲”或“种植中”。如果直接在后端返回结果里转换那列表接口和编辑回显接口的处理就会不一致容易出bug。我的处理方式是在前端用Element UI的formatter函数转换展示文本。el-table-column label地块状态 width120 template slot-scopescope el-tag :typescope.row.status 1 ? success : info {{ scope.row.status 1 ? 种植中 : 空闲 }} /el-tag /template /el-table-column样式上我也做了一点增强。种植中的地块用绿色的Tag标识空闲的用灰色Tag标识这样管理员一眼就能看到哪些地块正在使用中。种植中地块旁边还会显示当前种植的作物名称这个数据来自联表查询后端在返回地块列表的时候用SQL把关联的种植记录和作物名称一并查出来。4.4 环境监测图表的可视化实现环境数据的可视化是智慧菜园管理系统的一个重要亮点。我选用了ECharts作为图表库它功能强大图表类型丰富而且Vue版本有封装好的组件库可以无缝衔接。实现的方式是前端页面加载时调用后端的环境数据查询接口获取指定地块最近24小时的环境数据列表然后通过ECharts的line图表展示温度和湿度的变化趋势。查询接口的关键参数是plotId和timeRange后端根据时间范围筛选数据按时间升序返回。这里有一个数据量的问题需要注意。如果按5分钟一条数据存储24小时就有288条数据画折线图时数据点太多会导致图表渲染卡顿。我在后端查询接口做了降采样处理如果查询时间范围超过24小时就按小时做平均聚合。方法是在SQL里使用DATE_FORMAT把记录时间格式化到小时级别再按小时聚合计算平均值。SELECT DATE_FORMAT(record_time, %Y-%m-%d %H:00:00) AS time_point, AVG(temperature) AS avg_temp, AVG(humidity) AS avg_humidity, AVG(light_intensity) AS avg_light FROM environment_log WHERE plot_id #{plotId} AND record_time #{startTime} GROUP BY DATE_FORMAT(record_time, %Y-%m-%d %H:00:00) ORDER BY time_point ASC这种做法既保证了图表趋势的清晰度又避免了前端处理大量数据点的性能问题。实际调测下来7天数据的趋势图渲染非常流畅。4.5 前端Axios请求封装与拦截器Axios请求封装这个环节非常重要。如果直接在页面组件里写axios.get(/api/xxx)代码会大量重复而且接口报错处理也很混乱。我专门封装了一个request.js模块统一处理请求头、响应拦截、错误提示。import axios from axios; import { Message } from element-ui; import router from ./router; const service axios.create({ baseURL: /api, timeout: 10000 }); // 请求拦截器自动携带token 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) { Message.error(登录状态已过期请重新登录); localStorage.removeItem(token); router.push(/login); } else { Message.error(网络连接异常请稍后重试); } return Promise.reject(error); } ); export default service;这样一来页面里调用接口就非常简洁了不需要每个页面都做错误处理。而且后端返回的code、message、data结构也在这个拦截器里统一解构前端组件拿到数据直接就能用。5. 系统部署上线与运维实践5.1 本地环境准备与构建系统开发完成后要部署上线第一步是准备环境。我在本地Windows环境演示部署完整的环境包括JDK 8、Maven 3.6、Node.js、MySQL 5.7。首先说后端构建。在项目根目录执行Maven打包命令mvn clean package -DskipTests这个命令会跳过单元测试直接打包成一个可执行的jar包默认在target目录下文件名通常是smart-garden-0.0.1-SNAPSHOT.jar。为什么跳过测试因为很多项目里的测试类写得不完整运行时会报错打包就会中断。跳过测试能保证构建不被无关的测试代码阻碍但这只适用于没有完整测试覆盖的交付场景。然后说前端构建。前端项目在根目录执行npm install npm run build构建完成后会在dist目录下生成一堆静态文件包括index.html和static目录。这些就是要部署到Nginx的静态资源。5.2 Linux服务器部署实战服务器部署我推荐用Linux系统我实际用的是CentOS 7。部署的步骤分五步安装JDK和Nginx、初始化MySQL数据库、上传后端jar包并启动、上传前端静态文件并配置Nginx、访问验证。后端jar包启动命令我建议用nohup方式后台运行同时把日志重定向到文件方便排查问题nohup java -jar smart-garden-0.0.1-SNAPSHOT.jar \ --spring.profiles.activeprod \ --server.port8080 \ /opt/smart-garden/logs/app.log 21 这里我使用了--spring.profiles.activeprod参数指定生产环境配置。我在application-prod.yml配置文件中把数据库连接地址、Redis地址等环境相关的配置集中管理部署时只需要改一个配置文件就可以。这么做的一个直接好处是开发环境、测试环境、生产环境的配置互不干扰。Nginx配置方面核心是配置一个server块将监听80端口的请求分为两部分静态文件请求直接返回/api开头的请求反向代理到后端的8080端口。server { listen 80; server_name your-domain.com; root /opt/smart-garden/web; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }这里有一个坑特别要注意proxy_pass http://127.0.0.1:8080/;后面有斜杠意味着会把/api/这个前缀去掉后转发到后端。比如前端请求/api/login实际转发到后端是http://127.0.0.1:8080/login。如果后端接口本身没有/api前缀就必须这么配。如果你在后端也加了一个/api的context-path那proxy_pass后面就不应该加斜杠。这个细节弄错了会导致接口404还不好排查。5.3 Docker部署方案对比与选择除了传统部署我还提供了一套Docker Compose部署方案。这套方案把MySQL、后端服务和前端Nginx都封装到容器里一键启动。Docker部署最大的优势是环境一致性本地跑起来什么样服务器上就是什么样不会出现“本地好好的到服务器上就报错”的情况。劣势是很多开发者对Docker不够熟悉出了问题不好排查而且第一次拉取镜像耗时较长。我的做法是提供两套方案给使用者如果只是课程设计展示或小规模使用直接用传统部署就够了简单直观。如果是要给公司做快速交付或者在多台服务器上部署那用Docker Compose更省心。下面是一个简化的docker-compose.ymlversion: 3 services: mysql: image: mysql:5.7 container_name: smart-garden-mysql environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: smart_garden ports: - 3306:3306 volumes: - ./mysql-data:/var/lib/mysql - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql restart: always backend: build: ./backend container_name: smart-garden-backend depends_on: - mysql ports: - 8080:8080 restart: always web: image: nginx:alpine container_name: smart-garden-web ports: - 80:80 volumes: - ./web/dist:/usr/share/nginx/html - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf depends_on: - backend restart: always这种部署方式未来如果要扩展比如加一个Redis容器做缓存或者加一个监控容器只需要在docker-compose.yml里加一个服务定义就行不需要改动现有服务。5.4 数据库初始化与迁移脚本管理数据库的初始化分两种场景。一种是全新安装直接在MySQL里执行init.sql脚本建库、建表、插入初始数据一步到位。另一种是数据库升级在已有数据的基础上执行增量脚本添加新表或新字段。我采用的是Flyway来做数据库版本管理这个工具可以在SpringBoot应用启动时自动执行未执行过的SQL脚本。init.sql的命名规则是V1__init.sql后续如果加新表就命名V2__add_table.sql这样版本管理非常清晰。数据库同步这一块我给客户提供了两种方式。一种是直接导出整库的SQL文件mysqldump -u root -p smart_garden smart_garden.sql另一种是只导出表结构mysqldump -u root -p --no-data smart_garden smart_garden_structure.sql迁移到目标服务器时先执行结构脚本再通过SOURCE命令导入数据。提示导出数据库时一定注意字符集MySQL命令行导出时加上--default-character-setutf8mb4参数否则中文数据会变成乱码。这是很多人容易忽略的问题。6. 常见问题排查与优化建议6.1 部署和开发中的典型问题汇总我在整个开发和部署过程中遇到了一些比较有代表性的问题这里整理成表格方便大家对照排查。问题现象原因分析解决方案前端请求后端接口报404Nginx反向代理路径配置不对proxy_pass的斜杠问题检查location /api/的proxy_pass是否按预期去掉了/api前缀后端启动报数据库连接失败数据库未启动、连接地址写错、账号密码不对确认MySQL服务状态检查application.yml中jdbc连接串中文数据显示为问号数据库表字符集不是utf8mb4建库时指定DEFAULT CHARSETutf8mb4连接串加characterEncodingutf8JWT登录后刷新页面失效令牌存在sessionStorage刷新后丢失改为使用localStorage存储令牌定时任务不执行启动类缺少EnableScheduling注解在SpringBoot启动类上添加EnableSchedulingnpm install安装失败Node版本过高或过低依赖安装超时使用Node 14.x版本设置淘宝镜像源npm config set registry https://registry.npmmirror.com服务器端口被占用之前启动过应用未正常关闭netstat -tlnp其中npm install安装失败这个问题在开发过程中反复出现过多次。一开始我本机装的是Node 18结果项目中用的一个依赖不兼容一编译就报错。后来把Node版本降到14就很稳定了。现在很多前端项目都开始使用pnpm或yarn来替代npm安装速度和依赖管理都好很多大家可以根据实际情况选择。6.2 查询性能优化实录系统运行一段时间后环境数据表的记录量增长很快。虽然这个规模的数据量并不会造成性能瓶颈但作为一个有追求的开发者我还是对几个高频查询做了优化。优化最大的两处一是在环境数据表增加了(plot_id, record_time)联合索引这个索引直接命中环境监测图表查询的条件二是种植记录的分页查询原来的SQL是先连接地块表和作物表再排序分页我在连接前先对planting_record按id排序并分页再连接查询关联表信息这样数据量大时效率提升明显。这里要说明一下MySQL的索引优化是一个很灵活的话题不是索引越多越好。索引会占用存储空间而且在插入、更新操作时会增加维护成本。首先要对查询频率高、数据量大的表建立合适索引然后通过EXPLAIN命令分析SQL的执行计划确认索引是否被正确使用。我见过很多开发者建了一堆索引结果SQL写的时对字段做了函数运算导致索引失效这算是比较常见的问题。6.3 系统安全加固与权限控制管理系统直接暴露在公网上安全这块不得不重视。我在这个项目中做了几层基本的安全防护。第一层是接口防刷。对登录接口增加了验证码校验同时做了登录失败的次数限制。同一IP在五分钟内连续失败5次会被锁定要等十分钟才能继续尝试。这个功能可以有效防止暴力破解密码。第二层是接口鉴权。除了登录接口和获取验证码接口其余接口都经过JWT拦截器校验。同时管理员接口和普通用户接口做了角色分离普通用户的令牌无法调用用户管理相关接口。第三层是预防SQL注入。在使用MyBatis时我坚持使用#{}占位符传参而不是${}拼接。#{}会被预编译为参数化查询从源头上杜绝SQL注入${}虽然在某些动态排序场景下比较灵活但如果直接拼接用户输入风险很高。第四层是前端权限控制。菜单和按钮根据用户角色动态渲染管理员和普通用户看到的界面不一样。前端的控制只是为了提升用户体验真正的安全防线还是在后端的接口鉴权这个原则一定要记住。6.4 系统扩展性思考项目交付之后我自己也在思考这个系统后续可以怎么扩展。总结下来有几个方向如果你在做类似的系统也可以参考。第一个方向是接入真实的物联网设备。目前的系统在环境数据模块预留了HTTP上报接口理论上只要设备端能按约定格式上报数据就能直接接入。实际设备还可以考虑设备注册、设备状态管理、离线告警等功能这些模块可以单独做一个“设备管理”菜单。第二个方向是增加视频监控能力。菜园现场安装摄像头前端通过WebRTC或HLS协议播放实时画面。现在前端播放m3u8格式的视频流非常成熟Vue中集成video.js或hls.js就能实现后端也不需要有额外的技术负担。第三个方向是引入数据分析。当环境数据和种植记录积累到一定规模后可以对不同作物、不同季节、不同地块的产量数据做分析帮助用户找到最优的种植策略。这块的基础数据就在环境数据表和收获记录表里只需要在统计模块增加一些聚合查询和图表展示即可。第四个方向是增加移动端适配。目前的前端页面是以PC为主要目标做开发的手机访问虽然能用但体验一般。计划中可以通过响应式布局优化或者直接开发一个小程序版本让用户可以在手机上随时查看环境数据和执行农事任务。7. 项目交付与使用体验的个人心得在反复测试和调优之后这套智慧菜园管理系统总算是稳定跑起来了。交付的内容包括完整的源码、数据库初始化脚本、详细的部署文档和一份简易的用户操作手册。朋友那边接手后自己照着部署文档在服务器上操作了一遍没有再遇到什么大问题主要是我在部署文档里把所有容易出错的地方都用加粗标注了确实帮了大忙。最后再分享几点我做这类项目的心得体会。第一先考虑业务边界再考虑技术实现。很多人在开发管理系统时容易被技术牵着走上来就考虑用什么框架、什么组件其实应该先画出业务流程图明确每个角色的操作场景再回过头来设计表和接口。我这次做智慧菜园第一步就是花了两天时间跟使用者聊清楚他们日常怎么管理菜园、最关心什么数据、什么是痛点然后才动手做的技术设计。第二部署文档的重要性不亚于源代码。说实话源码写得好只是项目成功了一半。如果部署文档写得不够细致使用者拿过去部署不起来这个项目就等于白做了。我每次交付项目都会花至少半天时间写部署文档把每一步操作、每一个可能报错的坑都写清楚。很多客户看到部署文档的第一反应都是“这比开发文档还详细”但正是这种细节才能让项目真正落地使用。第三给自己留一点演进的空间。我在开发时一直坚持接口返回格式统一、数据库字段命名规范、前端组件化拆分这些设计习惯让系统在后续迭代时能快速响应新需求。比如后来用户提出要在环境监测页面增加数据导出功能我只需要在后端加一个导出接口前端增加一个下载按钮前后不到一个小时就完成了。这套智慧菜园管理系统从设计到落地前前后后凝聚了很多实用的经验。希望这篇文章里关于数据库设计、后端实现、前端开发、部署上线的细节能够给正在做类似项目的你提供一些有价值的参考。也欢迎遇到具体问题的时候来交流咱们一起把管理系统做得更好。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

让代码自证清白:构建可验证交付的四层可信模型 2026/8/31 2:23:02

让代码自证清白:构建可验证交付的四层可信模型

很多开发者都有一个朴素的想法:只要我的代码写得好,项目自然会被人发现,使用的人自然会多起来。但从实际经验看,这个想法往往会在现实面前碰壁。代码写得好的开源项目无人问津,反而是那些文档清晰、构建规范、流程透明…

阅读更多 →
NFC支付戒指背后的安全芯片与天线设计挑战 2026/8/31 2:23:02

NFC支付戒指背后的安全芯片与天线设计挑战

2024年我第一次拿到一枚NFC支付戒指的测试样品时,第一反应不是“哇”,而是“这玩意儿到底怎么刷卡”。戒指直径不到20毫米,表面光滑,没有按钮、没有充电口,看起来就是一件普通饰品。但把它贴近POS机读卡区,…

阅读更多 →
8款精选AI论文平台横向实测,本硕博避坑选型手册 2026/8/31 2:23:02

8款精选AI论文平台横向实测,本硕博避坑选型手册

前言:AI 写论文乱象频发,实测 8 款工具理清适配边界 每到毕业季,本科生、硕博生都会集中寻找 AI 论文辅助工具,市面各类写作软件层出不穷,但普遍存在几类硬伤:虚假参考文献、无法匹配本校格式、不支持公式代…

阅读更多 →
微服务配置中心核心机制与实践指南 2026/8/31 2:23:02

微服务配置中心核心机制与实践指南

配置中心是分布式系统里最容易轻视、出事时却最致命的一环。很多团队在微服务化初期,把配置散落在各个服务的application.yml里,靠人工通知、群聊同步来管理变更。等服务数量超过二十个,配置变更就需要发版、重启、等审批,一次错误…

阅读更多 →
别再肉眼挑线圈!无线充电线圈选型实战指南 2026/8/31 2:23:02

别再肉眼挑线圈!无线充电线圈选型实战指南

选无线充电线圈,别再用肉眼挑挑了做无线充电项目几年,我发现一个特别有意思的现象:很多工程师在设计前期,把精力全放在功率级、控制算法、通信协议上,到了线圈这一步,随手拿个现成规格书或者网上搜个尺寸差…

阅读更多 →
三极管放大电路详解:直流电源与偏置供电的作用及共射放大验证 2026/8/31 2:18:02

三极管放大电路详解:直流电源与偏置供电的作用及共射放大验证

这次我们来看一个经典问题:三极管的放大到底是什么放大?为什么一定要接直流电源?为什么还要单独加一个偏置供电?很多人在面包板上搭共射放大电路时会遇到同一个现象:信号源接上去,输出波形不是没反应&#…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞