拓冰建站拓冰建站
首页 / 资讯中心 / 正文

SpringBoot+Vue前后端分离:大棚蔬菜管理系统开发实践

简介一份基于SpringBoot与Vue.js的大棚蔬菜管理系统Java毕业设计论文面向计算机相关专业的学生和需要开发同类管理系统的开发者用于解决传统管理方式在时间、地点上的限制实现蔬菜信息的在线化管理。包内为1个docx文档约5.32MB内容涵盖系统需求分析、架构设计、数据库设计以及前后端分离实现等完整章节。论文详细介绍了用户模块与管理员模块的功能划分包括注册登录、蔬菜信息管理、智能调温、自动灌溉、订单处理等并涉及MVC模式、RESTful API、OAuth2.0、权限管理与数据安全等关键技术点。文档结构完整包含中英文摘要、目录、绪论、关键技术介绍及总结等内容可作为毕业设计撰写范本。目前已有158人学习下载作为毕业设计参考或项目开发蓝本能帮助读者快速理清SpringBoot与Vue.js整合的开发流程、数据库表设计与接口实现思路值得借鉴。1. 大棚蔬菜管理系统一个前后端分离的典型样本二十一世纪的信息化管理系统建设核心价值是把线下纸质流程搬到线上。传统大棚蔬菜管理靠人工登记蔬菜批次、库存、温度和灌溉时间数据分散且难追溯而基于SpringBootVue的大棚蔬菜管理系统把用户注册登录、蔬菜信息展示、在线客服、购物车以及管理员侧的智能调温、自动灌溉、订单管理全部收敛到一个在线管理平台中。它解决的核心问题是权限划分与数据同步用户看到的是可查询的蔬菜信息管理员掌握的是全量运营数据。对开发者而言这是一个标准的前后端分离Java项目样本完整覆盖了数据库建模、RESTful接口开发、角色权限控制、Vue前端交互与部署排错适合正在做课程设计、毕业设计或者想快速梳理SpringBoot全家桶项目结构的读者。2. SpringBoot与Vue的选型逻辑为什么是它们2.1 B/S架构与前后端分离的边界传统管理系统受限于时间与地点必须在特定电脑上安装客户端而B/S架构只需浏览器即可访问服务器部署一次用户侧零安装。这个项目选择B/S架构本质原因是业务场景对终端要求不高管理员在办公室维护数据用户在手机或电脑浏览蔬菜信息服务端统一升级不需要逐台设备更新。前后端分离后Vue负责SPA单页应用SpringBoot只提供API接口二者通过JSON交换数据后端不再关心页面渲染前端也不再直接拼接HTML这条边界让团队分工和后期维护都更清晰。2.2 SpringBoot在后端扮演的角色SpringBoot的核心优势是简化Spring配置内嵌Tomcat打包后一条命令即可运行。相比早期Spring项目手写XML配置SpringBoot通过自动配置把数据源、Web服务器、MyBatis等常用组件预置好开发者只需要关注业务代码。在蔬菜信息模块我习惯用一个Controller暴露接口而不是在Servlet里写一堆模板代码RestController RequestMapping(/api/vegetable) public class VegetableController { Autowired private VegetableService vegetableService; GetMapping(/list) public Result list(RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer limit) { return Result.success(vegetableService.pageList(page, limit)); } }这段代码里RestController表示当前类所有方法直接返回JSON由SpringBoot自动序列化RequestMapping(/api/vegetable)定义接口前缀模块内所有对蔬菜的增删改查都走这个路径RequestParam接收分页参数defaultValue保证前端漏传时不会报空指针。分页查询是管理系统的高频场景所以pageList方法内部传入当前页和每页条数返回的Result统一封装了状态码、提示信息和数据体前端拿到后直接渲染即可。2.3 Vue在前端的作用域与交互方式Vue是渐进式框架核心库只关注视图层这决定了它可以被灵活嵌入现有页面也可以支撑完整的单页应用。在这个系统里我使用Vue Router做路由Vuex管理登录状态Element UI提供后台管理组件。Vue的数据绑定极大减少了手动操作DOM的频率蔬菜列表的渲染只需把接口返回的数组赋值给tableData页面会同步更新。与React相比Vue的模板语法更接近HTML后端工程师转型前端时上手成本更低。对于搜索条件、购物车加减数量这类局部状态Vue的响应式系统可以做到即时反馈用户不需要等页面刷新。2.4 从论文到工程MVC与RESTful API的实际落地论文中提到MVC模式实际工程中我把它拆成Controller、Service、Mapper三层。Controller层处理参数接收与结果包装Service层写业务规则Mapper层用MyBatis-Plus操作MySQL数据库。接口设计遵循REST风格资源用名词操作用HTTP方法GET /api/vegetable/list表示查询列表POST /api/vegetable/add表示新增DELETE /api/vegetable/{id}表示删除。关于OAuth2.0论文里提得很正式但真实场景是纯前后端分离且没有第三方登录接入用OAuth2.0反而会增加令牌管理和回调地址的复杂度我最终采用JWT生成短期令牌配合后端拦截器实现角色权限判断。这个取舍在中小型管理系统里很常见核心目标是在安全性和开发成本之间找到平衡。3. 数据库设计从ER图到数据表的取舍3.1 核心实体关系梳理系统涉及用户、蔬菜种类、蔬菜信息、订单、智能调温、自动灌溉六个主要实体。用户与订单是一对多关系一个用户可以下多个订单蔬菜种类与蔬菜信息是一对多一个种类下包含多个蔬菜品种。智能调温和自动灌溉则是一张大棚环境记录表保存设备上报的温度、湿度和操作时间。在设计时我没有过度追求范式化蔬菜信息表里直接冗余了蔬菜种类名称因为查询列表时经常需要同时展示种类冗余字段可以省掉一次联表查询对管理系统的查询性能更友好。3.2 用户表与权限设计用户表是系统权限控制的基础字段包括主键、用户名、密码、角色和创建时间。密码不能明文存储项目中使用BCrypt加密每次登录时比对密文而不是明文。角色字段既决定前端能看到哪些菜单也决定后端接口是否允许调用。用户表建表语句如下CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键, username varchar(100) NOT NULL COMMENT 用户名, password varchar(200) NOT NULL COMMENT 密码, role varchar(50) DEFAULT 用户 COMMENT 角色管理员/用户, addtime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;AUTO_INCREMENT让用户ID自增不用业务代码生成role字段用字符串而不是整数直接看出是管理员还是普通用户调试时更直观utf8mb4字符集支持更全面的字符避免中文乱码和某些生僻字录入失败。addtime用DEFAULT CURRENT_TIMESTAMP可以由数据库自动记录注册时间减少Java代码里的手动赋值。3.3 蔬菜信息表与订单表的字段陷阱蔬菜信息表字段包括蔬菜编号、名称、种类、封面、产地、采摘日期、保质期、单限、库存、点击次数、价格。其中“单限”指单个用户最多购买数量这个字段必须配合库存一起校验。价格字段我建议用decimal而不是float或double因为浮点数在计算总价时会出现精度误差影响订单金额展示。订单表必须冗余商品名称和图片这点很容易被忽略。用户下单之后蔬菜信息可能被管理员修改名称或下架如果订单表只存商品ID历史订单关联当前商品就会错乱。订单表核心结构如下CREATE TABLE orders ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键, orderid varchar(50) NOT NULL COMMENT 订单编号, goodid bigint(20) DEFAULT NULL COMMENT 商品ID, goodname varchar(200) DEFAULT NULL COMMENT 商品名称, picture text COMMENT 商品图片, buynumber int(11) DEFAULT NULL COMMENT 购买数量, userid bigint(20) DEFAULT NULL COMMENT 用户ID, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表;orderid使用独立编号而不是主键方便对接物流和后台检索picture字段存的是图片URL路径不是图片二进制内容否则会撑爆数据库表。userid建立普通索引因为用户在个人中心查询订单时userid会作为查询条件。3.4 智能调温与自动灌溉的数据模型智能调温和自动灌溉本质是物联网设备数据落库。智能调温表记录大棚编号、名称、位置、面积、当前温度、目标温度和调温时间自动灌溉表记录湿度、是否灌溉和灌溉时间。这里的核心设计点是调温时间和灌溉时间要加索引。因为管理端列表页通常按时间倒序展示设备最近一次操作记录没有索引时大表查询会变成全表扫描。建表语句CREATE TABLE smart_temp ( id bigint(20) NOT NULL AUTO_INCREMENT, peng_bianhao varchar(50) DEFAULT NULL COMMENT 大棚编号, peng_mingcheng varchar(100) DEFAULT NULL COMMENT 大棚名称, position varchar(200) DEFAULT NULL COMMENT 位置, area decimal(10,2) DEFAULT NULL COMMENT 面积, current_temp decimal(5,2) DEFAULT NULL COMMENT 当前温度, target_temp decimal(5,2) DEFAULT NULL COMMENT 目标温度, adjust_time datetime DEFAULT NULL COMMENT 调温时间, PRIMARY KEY (id), KEY idx_adjust_time (adjust_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT智能调温表;decimal(5,2)表示最多五位数字其中两位是小数可存储的最大温度是999.99足够覆盖大棚环境温度。KEY idx_adjust_time是普通索引专门加速时间范围查询例如统计一周内的调温频率。4. 后端核心模块实现权限控制与业务接口4.1 登录鉴权与角色权限划分登录流程在后端做的事很简单接收用户名和密码校验通过后生成JWT令牌返回给前端。前端把令牌存入localStorage后续所有请求在请求头携带Authorization。后端用拦截器统一解析令牌并根据接口定义的权限码决定是否放行。下面是一个简化版拦截器用于拦截需要管理员权限的接口public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token null || !token.startsWith(Bearer )) { response.setStatus(401); return false; } String role JwtUtil.parse(token); if (!admin.equals(role)) { response.setStatus(403); return false; } return true; } }preHandle在请求进入Controller之前执行返回false时请求直接终止。401表示未登录前端会跳转到登录页403表示用户角色没有权限前端通过axios响应拦截器弹出“无权限”提示。需要特别注意的是拦截器必须配置白名单例如/api/user/login、/api/vegetable/list这些接口需要放行否则用户连登录都进不来。4.2 蔬菜信息模块的RESTful接口实现蔬菜信息是所有业务的核心接口设计直接决定前端联调的效率。/api/vegetable/add用于管理员新增蔬菜实现时先做重名校验避免同一种蔬菜被重复录入PostMapping(/add) public Result add(RequestBody Vegetable vegetable) { Vegetable exist vegetableService.getOne( new QueryWrapperVegetable().eq(shucaimingcheng, vegetable.getShucaimingcheng())); if (exist ! null) { return Result.error(500, 蔬菜名称已存在); } vegetableService.save(vegetable); return Result.success(); }RequestBody的作用是把前端提交的JSON自动转换成Vegetable实体字段名需要和前端参数一一对应。QueryWrapper是MyBatis-Plus的条件构造器eq表示相等条件。这里的重名校验不是绝对并发安全如果两个管理员同时新增同名蔬菜理论上还会插入成功但管理系统的并发量很低这个判断已经足够。真正的高并发场景应该给蔬菜名称加唯一索引不过那会增加异常处理的复杂度。4.3 智能调温与自动灌溉的逻辑处理智能调温和自动灌溉在论文中只是简单的增删改查实际开发中更值得做的是设备数据联动。智能调温的自动调温逻辑是比较当前温度和目标温度如果当前温度偏高就生成一条调温记录并触发硬件控制接口。Service层可以这样写Service public class TempService { Autowired private SmartTempMapper tempMapper; public void autoAdjust() { ListSmartTemp tempList tempMapper.selectList(null); for (SmartTemp temp : tempList) { if (temp.getCurrentTemp() temp.getTargetTemp()) { temp.setAdjustTime(new Date()); tempMapper.updateById(temp); // 调用硬件控制接口例如 HTTP POST 到温度控制设备 } } } }selectList(null)表示全量查询如果大棚数量多这里应该按状态过滤只处理异常设备。updateById只更新非空字段所以adjustTime单独赋值。实际生产环境autoAdjust可以交给Spring的Scheduled定时任务每分钟执行一次也可以由设备端消息触发。这个业务本身不复杂核心是让管理系统的数据与真实环境状态保持同步。4.4 订单与购物车的并发注意点购物车下单流程虽然简单但库存扣减需要防超卖。用户多次点击提交按钮或者多个用户同时购买同一款蔬菜常规的“先查库存再更新”会出问题。正确做法是把判断库存和扣减库存合并到一个SQL操作中boolean flag vegetableService.update(new UpdateWrapperVegetable() .setSql(kucun kucun - num) .eq(id, goodId) .ge(kucun, num)); if (!flag) { return Result.error(库存不足); }setSql(kucun kucun - num)让数据库在字段原值上做减法而不是先读后写ge(kucun, num)是条件判断库存必须大于等于购买数量才会更新成功。这个写法可以避免并发超卖但num是前端传入的如果直接把用户输入拼接进SQL存在注入风险生产环境应改用参数占位符或先校验类型。这里的flag为false时说明库存不够接口直接返回错误提示。接口权限划分可以整理成一张表格方便后端开发与前端联调时对照参考接口路径请求方式访问角色说明/api/user/loginPOST公开登录获取令牌/api/vegetable/listGET公开蔬菜列表/api/vegetable/addPOST管理员新增蔬菜/api/order/addPOST用户提交订单/api/smarttemp/updatePUT管理员修改调温目标表格中的公开接口不需要拦截器校验令牌用户接口只需要登录管理员接口必须校验角色这种粒度可以在拦截器里配置不同的路径规则。5. 前端Vue实战从登录页到数据可视化5.1 项目初始化与依赖安装Vue项目初始化最省事的方式是用官方脚手架Node环境准备好后执行命令创建工程并安装依赖。有人会遇到vue安装及环境配置的问题其实就是Node版本和npm源的问题配合nvm切换Node版本基本能解决。命令如下npm install -g vue/cli vue create greenhouse-admin cd greenhouse-admin npm install axios vue-router vuex element-ui echartsnpm install -g全局安装Vue CLI安装后才有vue命令vue create创建项目模板axios负责发HTTP请求vue-router管理路由vuex管理登录令牌与用户信息element-ui提供表格、表单、弹窗等后台组件echarts用于绘制温度和湿度变化曲线。安装完成后我在src目录下按功能建立api、router、store、views子目录让代码结构清晰。5.2 路由守卫与登录状态管理前端路由守卫是权限控制的第一道门槛。没有令牌的用户访问任何页面都应该被重定向到登录页。实现逻辑很简单router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.path /login) { next() } else if (!token) { next(/login) } else { next() } })beforeEach是Vue Router的全局前置守卫在每次路由跳转前执行。next()放行当前跳转next(/login)强制跳转到登录页。这段代码只判断了有无令牌实际项目中还应该根据用户角色动态生成可访问的路由表避免管理员页面在普通用户菜单中显示。token放在localStorage里可以跨页面保持登录状态但刷新页面后需要从存储中恢复用户信息到vuex。5.3 axios请求封装与后端接口对接axios封装的核心是统一处理请求头、超时时间和错误状态。我在src/api/request.js中创建实例并设置请求拦截器import axios from axios const request axios.create({ baseURL: /api, timeout: 5000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer token } return config }) export default requestaxios.create生成一个独立的请求实例baseURL设置为/api这样调用request.get(/vegetable/list)实际请求的是/api/vegetable/list。请求拦截器在每个请求发出前自动附加Authorization头后端拦截器通过这个头解析用户角色。统一配置后Vue组件里不需要再手动拼接token。如果后端返回401可以在响应拦截器里统一清除登录状态并跳转登录页避免每个页面重复写判断逻辑。5.4 蔬菜信息展示与购物车交互蔬菜信息列表页面通常用表格加搜索条件实现。用户端更注重视觉展示我会用卡片布局配合分页组件展示蔬菜图片、价格和库存。购物车交互的重点是数量不能超过“单限”字段每次加减都需要校验changeNum(row, type) { if (type add) { if (row.num row.onelimittimes) { this.$message.warning(超过单次限购数量) return } row.num } else { if (row.num 1) return row.num-- } }onelimittimes是后端返回的单限字段row.num是本地购物车数量。这里只做了前端限制后端下单接口仍然要再次校验库存与单限前端校验只为了提升用户体验不能替代后端安全逻辑。系统首页的智能调温数据可视化我使用echarts在mounted中初始化折线图并在beforeDestroy里销毁图表实例防止路由切换后内存泄漏。6. 系统测试与部署排错我自己踩过的几个坑6.1 测试用例设计功能测试之外权限测试是重点。我用Postman模拟普通用户令牌请求后台管理接口确认返回403而不是200测试购物车超卖时用两个账号同时对一个库存为1的蔬菜下单验证只有一个成功。这些用例不需要写自动化脚本但每次改接口都要回归一遍。6.2 前端跨域与代理配置开发环境最常见的报错是跨域。Vue CLI开发服务器默认端口是8080后端接口监听8080看似端口一致但前后端分离后前端请求走的是Node开发服务器需要配置代理转发module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }target指向后端服务地址changeOrigin必须设置为true这样后端拿到的请求头是后端的域名而不是前端开发服务器。部署到服务器后我用Nginx把静态文件和/api反向代理到SpringBoot进程Nginx配置里同样要处理proxy_set_header Host $host否则后端重定向时会出现IP异常。6.3 SpringBoot打包部署与MySQL时区打包发布时执行mvn clean package生成可执行JAR然后用java -jar启动。这里最常遇到的坑是MySQL时区报错连接串缺少serverTimezone会引发The server time zone value异常。正确配置是在application.yml的JDBC URL上追加参数spring: datasource: url: jdbc:mysql://localhost:3306/greenhouse?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiAsia/Shanghai表示使用北京时间避免数据库与操作系统时区不一致导致时间字段偏移八小时。6.4 一个调温接口的边界处理技巧最后说一个接口边界校验的细节。智能调温接口接收管理员提交的目标温度原始版本只判断了非空结果保洁阿姨误操作输入-50系统频繁触发降温报警。后来我在实体字段上加了Bean Validation注解DecimalMin(value 0, message 温度不能低于0) DecimalMax(value 40, message 温度不能高于40) private Double targetTemp;DecimalMin和DecimalMax会在SpringBoot参数校验阶段拦截非法值根本不会进入Service层。如果不同操作需要不同范围例如冬季目标温度下限可以更低我会定义多个校验分组在Validated注解中指定分组类型避免一套规则写死。接口层的边界校验是低成本高效率的防线比在Service层写一堆if判断要规范得多。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门