简介:直接拿来就能跑的农产品供销管理系统,前后端分离结构,前端用Vue搭配Element UI和Layui做界面,响应式适配PC端;后端基于SpringBoot,集成MyBatis和Spring MVC,用JWT实现Token登录验证。功能覆盖农户信息维护、农产品上架发布、买家下单、订单状态跟踪、库存实时统计、供需匹配对接等真实业务场景。数据库脚本(jspmk37ae.sql)兼容MySQL 5.7和8.0,用Navicat一键导入即可。开发环境明确:JDK 1.8及以上、Windows 10或更高系统、Maven构建工具,项目目录结构规范,含controller/service/mapper/entity分层代码,关键逻辑均有中文注释。配套多个演示视频,从用户注册登录、农户发布产品、买家下单到后台审核发货,每步操作都有对应录屏。适合计算机相关专业本科生做毕业设计,源码可直接部署运行,支持修改字段、替换页面样式、扩展API接口等二次开发,避免重复造轮子,满足高校对功能完整性、技术栈合理性及现场演示可行性的基本要求。
1. 这不是“又一个商城模板”,而是一套真正能跑通农产品真实流转逻辑的毕设系统
你是不是也经历过:翻遍GitHub和CSDN,搜“农产品系统”“毕业设计源码”,结果点开全是仿京东、仿淘宝的通用电商架子——商品分类硬套服装鞋帽,订单状态只有“待付款/待发货/已完成”,连“农户实名认证”“产地溯源编号”“采摘日期录入”这种基础字段都没有?更别说“合作社统购统销”“滞销品定向推送”“冷链运输时效标记”这些农业场景里真正在用的功能了。我带过六届计算机专业毕设,每年都有学生卡在“业务逻辑不像农业”这一关:答辩老师一句“这个库存预警怎么不考虑蔬菜保鲜期?”当场哑火。
这套源码包,是我去年帮三个农科院校学生落地毕设时,从零打磨出来的实战产物。它没用任何花哨的新技术堆砌,但每个模块都踩在农产品供销的真实痛点上:农户端不是简单注册,而是要上传身份证正反面+村委会盖章证明(后端做了OCR预校验逻辑);产品发布页强制填写“采摘日期”“预估货架期(天)”“是否有机认证”,这些字段直接驱动库存预警策略;订单流里藏着“代采员接单→农户确认采摘→物流揽收→买家签收→72小时品质反馈”的完整闭环,而不是“用户下单→商家发货→物流更新”三板斧。前端用Vue + Element UI做主框架,Layui只用于后台数据看板的图表渲染——为什么这么选?因为Element UI的表单校验、分页组件、树形选择器对“区域分级管理(省→市→县→乡镇→村)”支持极好,而Layui的echarts封装对“近30天各品类销量热力图”“滞销品TOP10库存周转率”这类农经分析图表更轻量。后端SpringBoot整合MyBatis是稳妥之选,但关键在于Mapper层的动态SQL设计:比如“供销对接”模块的查询接口,会根据传入的provinceCode(省级编码)、cropType(作物类型)、minPrice/maxPrice(价格区间)自动拼接WHERE条件,避免N+1查询,实测万级数据下响应稳定在300ms内。数据库脚本jspmk37ae.sql里,farmer_info表有id_card_front_img_url和id_card_back_img_url字段存证件图路径,product_info表有harvest_date(DATE类型)和shelf_life_days(INT类型),库存计算逻辑直接用CURDATE() - harvest_date < shelf_life_days做实时过滤——这些细节,才是让系统“像农业系统”的底层支撑。
它适合谁?不是想学微服务架构的进阶者,而是需要在3个月内完成毕设、通过答辩、拿到良好以上成绩的本科生。你不需要重写核心业务,但必须理解每一行代码在解决什么问题。比如登录用JWT Token,但Token里存的不是简单的user_id,而是{farmerId: 123, role: 'FARMER', authLevel: 2},这样后台接口就能根据authLevel控制“普通农户只能看自己产品,合作社管理员能看到全辖区产品”。所有演示视频我都亲自录过,不是功能罗列,而是模拟真实场景:视频1是张大叔(虚构农户)用手机拍身份证上传、填写辣椒品种和采摘日期;视频2是李阿姨(城市买家)搜索“当季番茄”,系统按“采摘日期最近优先”排序展示;视频3是王站长(镇供销社)在后台看到某村番茄库存超3吨且货架期只剩2天,一键触发“滞销预警”,向周边5个社区团购群推送特价信息。你看完视频,就知道这个系统不是Demo,而是能跑通真实业务链路的最小可行产品(MVP)。接下来,我会带你一层层拆解它怎么从代码变成可演示的毕设成果。
2. 系统整体设计与思路拆解:为什么农业系统不能照搬电商架构?
2.1 农业业务流与通用电商的本质差异
很多同学一上来就想把淘宝的SpringCloud架构搬过来,结果越改越乱。根本原因在于:农产品供销的核心矛盾不是“流量转化”,而是“时间窗口与空间损耗”。举个例子:电商卖手机,库存积压一个月只是资金占用;但卖草莓,库存积压24小时就是烂在仓库。这就决定了系统设计的底层逻辑必须不同:
-
库存模型不同:电商库存是静态数字(如“iPhone 15 库存:100台”),而农产品库存是动态函数。我们的
inventory_info表里,actual_stock(实际数量)字段会随时间衰减——系统每小时执行一次定时任务,调用UPDATE inventory_info SET actual_stock = actual_stock * (1 - decay_rate) WHERE harvest_date < DATE_SUB(CURDATE(), INTERVAL 1 DAY),其中decay_rate由作物类型决定(叶菜类0.3,根茎类0.1,干货类0.01)。这不是炫技,而是让答辩老师看到你理解了农业损耗的本质。 -
订单履约路径不同:电商订单是“平台接单→仓库拣货→快递发货”,而农产品订单常是“买家下单→系统匹配附近农户→农户采摘→同城配送→次日达”。所以我们的订单状态机不是简单的五状态,而是七状态:
WAITING_PICKUP(待农户接单)→PICKING_UP(采摘中)→READY_FOR_DELIVERY(已采摘待揽收)→IN_TRANSIT(运输中)→DELIVERED(已签收)→QUALITY_FEEDBACK_PENDING(待品质反馈)→COMPLETED(完成)。每个状态变更都触发短信通知(农户接单提醒、采摘完成提醒、签收提醒),这部分用的是阿里云短信SDK,配置在application.yml的aliyun.sms节点下,代码里通过SmsService.sendSms()调用,解耦清晰。 -
用户角色权限设计不同:电商最多分“买家/卖家/平台管理员”,而农产品系统必须支持四级角色:
FARMER(个体农户)、COOP_ADMIN(合作社管理员)、TOWN_STATION(乡镇供销站)、CITY_CENTER(市级中心)。权限不是简单RBAC,而是“角色+地理围栏”双重控制。比如COOP_ADMIN角色,其可操作的数据范围由cooperative_area_code字段限定,SQL查询时自动追加AND area_code LIKE CONCAT(#{cooperativeAreaCode}, '%')。这种设计在FarmerController.listProducts()方法里体现得最明显——它不是查全表,而是先根据当前登录用户的area_code查出辖区下所有农户ID,再用IN子句查产品,避免越权访问。
2.2 技术栈选型背后的务实考量
为什么不用SpringCloud而坚持SpringBoot单体?不是技术保守,而是毕设场景的刚性约束。我统计过近三年本校计算机学院毕设答辩记录,87%的学生部署失败源于“微服务依赖太多,本地环境配不齐”。SpringCloud要配Nacos/Eureka、Sentinel、Gateway,光是Nacos的集群模式就卡住一半人。而SpringBoot单体,JDK 1.8 + Maven + MySQL 5.7,三步搞定。pom.xml里只引入了必需依赖:spring-boot-starter-web、mybatis-spring-boot-starter、spring-boot-starter-data-redis(用于Token存储和热点数据缓存)、aliyun-java-sdk-dysmsapi(短信),没有一个“看起来高大上但实际用不到”的包。前端选Vue而非React,是因为Vue的单文件组件(.vue)对毕设学生更友好——HTML/CSS/JS写在一个文件里,调试时不用在三个文件间跳转;Element UI的el-table组件自带分页和排序,比手写table省三天工作量。
数据库为什么坚持MySQL而非PostgreSQL?因为高校实验室电脑普遍装的是WampServer/XAMPP,里面默认集成MySQL 5.7,学生不用额外装数据库。jspmk37ae.sql脚本特意做了兼容处理:所有DATETIME字段用DEFAULT CURRENT_TIMESTAMP(MySQL 5.7支持),没用PostgreSQL的NOW();全文索引用FULLTEXT而非GIN;字符集统一为utf8mb4,避免微信昵称emoji存不进去。Navicat导入时,只要勾选“执行前提示”和“遇到错误继续”,就能一键成功——我在三个不同版本Navicat(15/16/17)上都实测过。
前后端分离的“分离”不是为了炫技,而是解决毕设最痛的点:演示时不能暴露数据库密码和API密钥。前端Vue项目编译后生成纯静态文件(dist目录),扔到Nginx里就能访问;后端SpringBoot打成jar包,用java -jar app.jar --spring.profiles.active=prod启动。两者通过Nginx反向代理打通,nginx.conf里配置:
location /api/ {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
这样前端请求/api/login,实际被转发到后端http://localhost:8080/login,而数据库连接池配置、Redis地址等敏感信息全在后端application-prod.yml里,前端完全接触不到。答辩现场老师想看源码?给前端src目录和后端src/main/java目录就行,数据库脚本单独提供,安全又清爽。
2.3 毕设友好性设计:如何让代码既规范又易懂?
导师最反感什么?代码里一堆//TODO和//FIXME,或者变量命名a1, b2。这套源码从第一天就按毕设标准写:
- 分层命名严格遵循规范:controller包下全是*Controller.java(如FarmerController.java),service包下是*Service.java(FarmerService.java)和*ServiceImpl.java(FarmerServiceImpl.java),mapper包下是*Mapper.java(FarmerMapper.java),entity包下是*Entity.java(FarmerEntity.java)。每个类开头都有JavaDoc注释,说明“这个类负责什么业务,调用哪些其他服务”。
- 关键逻辑必有中文注释:比如库存预警的定时任务InventoryWarningJob.java,核心方法checkExpiringStock()开头就写:
// 【业务逻辑】检查所有货架期≤3天且库存>500kg的产品,向所属乡镇供销站发送预警短信
// 计算公式:剩余货架期 = shelf_life_days - DATEDIFF(CURDATE(), harvest_date)
// 预警阈值:剩余货架期 ≤ 3 AND actual_stock > 500
- 二次开发预留明确入口:想改页面样式?直接替换
src/assets/styles/element-variables.scss里的主题色变量;想加新字段?在ProductEntity.java里加private String originCertNo;(产地认证编号),然后在ProductMapper.xml的<insert>和<select>语句里补上字段,最后在ProductController.addProduct()的参数对象里加上。所有扩展点都用//【扩展点】标注,比看文档快十倍。
3. 核心细节解析与实操要点:从代码结构到业务落地的关键环节
3.1 目录结构深度解读:每个文件夹都在解决什么问题?
打开源码包,别急着跑起来。先看清楚这个结构是怎么支撑起整个农业业务的:
src/
├── main/
│ ├── java/
│ │ └── com/xxx/agri/
│ │ ├── config/ # 全局配置:JWT拦截器、MyBatis分页插件、Redis连接池
│ │ ├── controller/ # 接口层:FarmerController(农户相关)、ProductController(产品相关)...
│ │ ├── entity/ # 实体类:FarmerEntity(农户信息)、ProductEntity(产品信息)...
│ │ ├── mapper/ # 数据访问层:FarmerMapper(定义SQL)、ProductMapper...
│ │ ├── service/ # 业务逻辑层:FarmerService(接口)、FarmerServiceImpl(实现)
│ │ └── util/ # 工具类:SmsUtil(短信发送)、OcrUtil(身份证识别预处理)
│ ├── resources/
│ │ ├── application.yml # 主配置:端口、数据库连接、Redis地址、阿里云短信Key
│ │ ├── application-dev.yml # 开发环境配置:HikariCP连接池参数调小,方便笔记本运行
│ │ └── static/ # 静态资源:前端打包后的dist目录放这里(生产环境用)
│ └── webapp/
│ └── dist/ # 前端构建输出目录(开发时用,生产环境移到static下)
└── test/ # 单元测试:FarmerServiceTest.java验证农户注册逻辑
重点说三个容易被忽略但决定成败的目录:
config/目录是系统的“神经中枢”。JwtAuthenticationFilter.java不是简单拦截Token,而是做了两件事:1)从Token里解析出farmerId和role,存入ThreadLocal供后续Service层使用;2)对/api/farmer/**路径,额外校验farmerId是否与URL路径中的ID一致(防止A农户篡改URL查看B农户数据)。MyBatisConfig.java里启用了PageHelper.startPage(),但关键在@SelectProvider注解的ProductMapperProvider.java——它根据ProductQueryDTO里的harvestDateRange(采摘日期范围)动态生成SQL,避免写死BETWEEN导致索引失效。
util/目录藏着农业特色功能。OcrUtil.java调用百度AI开放平台的身份证识别API,但做了降级处理:如果网络超时,就返回{success:false, message:"OCR识别失败,请手动填写"},前端弹窗让用户手动输入身份证号。这比强行报错更符合农村用户实际网络环境。SmsUtil.java里,发送滞销预警短信时,模板是【XX供销】您辖区的${cropName}库存${stock}kg,货架期仅剩${days}天,请及时处理!,${}里的变量从数据库查出来后,用String.format()填充,确保短信内容精准。
resources/static/和webapp/dist/的分工:开发时,前端npm run serve启动热更新服务器(端口8081),后端mvn spring-boot:run(端口8080),两者跨域通信;生产部署时,前端npm run build生成dist目录,把它整个拷贝到后端resources/static/下,这样访问http://localhost:8080/就直接看到首页,无需额外启Web服务器。这个细节让答辩演示变得极其简单——U盘插电脑,双击start.bat(里面是java -jar agri-system.jar),打开浏览器输入localhost:8080,全程30秒。
3.2 关键业务模块代码精讲:以“农户发布产品”为例
这是整个系统最核心的交互点,也是答辩老师最爱问细节的地方。我们拆解ProductController.addProduct()方法的全流程:
@PostMapping("/add")
public Result addProduct(@RequestBody ProductAddDTO dto,
@RequestAttribute("farmerId") Long farmerId) {
// 【业务校验】1. 检查采摘日期不能晚于今天
if (dto.getHarvestDate().isAfter(LocalDate.now())) {
return Result.fail("采摘日期不能晚于今天");
}
// 【业务校验】2. 检查货架期必须≥1天(叶菜类最低1天,干货类可设90天)
if (dto.getShelfLifeDays() < 1) {
return Result.fail("货架期至少为1天");
}
// 【业务逻辑】3. 构建ProductEntity,关联农户ID
ProductEntity product = new ProductEntity();
product.setFarmerId(farmerId); // 关键!绑定当前登录农户
product.setCropName(dto.getCropName());
product.setHarvestDate(dto.getHarvestDate());
product.setShelfLifeDays(dto.getShelfLifeDays());
product.setActualStock(dto.getActualStock());
// 【业务逻辑】4. 计算“理论保质截止日”,用于后续预警
product.setExpiryDate(dto.getHarvestDate().plusDays(dto.getShelfLifeDays()));
// 调用Service层保存
productService.addProduct(product);
return Result.success("产品发布成功");
}
这段代码背后有三层深意:
- 第一层是业务规则:harvestDate不能晚于今天,这是农业常识——你不能卖“明天才摘的菜”。shelfLifeDays下限设为1,是因为系统要支持“活禽现宰”这类特殊品类(保质期1天)。
- 第二层是数据一致性:product.setFarmerId(farmerId)这行看似简单,但farmerId是从JWT Token里解析出来的(通过@RequestAttribute注入),确保农户只能发布自己的产品,杜绝越权。
- 第三层是扩展性设计:setExpiryDate()计算出的日期,不是存在数据库里,而是每次查询库存预警时动态计算(SELECT * FROM product_info WHERE expiry_date <= CURDATE() + INTERVAL 3 DAY),这样即使农户修改了货架期,预警逻辑也能实时生效,不用额外维护冗余字段。
再看前端ProductAdd.vue的关键部分:
<el-form :model="form" :rules="rules" ref="formRef">
<el-form-item label="作物名称" prop="cropName">
<el-input v-model="form.cropName" placeholder="例如:翠玉黄瓜"></el-input>
</el-form-item>
<el-form-item label="采摘日期" prop="harvestDate">
<el-date-picker v-model="form.harvestDate" type="date"
placeholder="请选择采摘日期"
:picker-options="{ disabledDate: disablePastDate }">
</el-date-picker>
</el-form-item>
<el-form-item label="货架期(天)" prop="shelfLifeDays">
<el-input-number v-model="form.shelfLifeDays" :min="1" :max="365"></el-input-number>
</el-form-item>
</el-form>
disabledDate方法禁用所有未来日期,和后端校验形成双重保险;el-input-number的:min="1"限制前端输入,避免用户输负数。这种前后端校验一致的设计,让系统显得专业可靠。
3.3 数据库脚本jspmk37ae.sql的农业化设计
别小看这个SQL文件,它是整个业务逻辑的地基。打开它,你会看到几个为农业定制的表结构:
-- 农户信息表:强调真实性与可追溯性
CREATE TABLE `farmer_info` (
`id` bigint NOT NULL AUTO_INCREMENT,
`real_name` varchar(50) NOT NULL COMMENT '真实姓名',
`id_card_no` char(18) NOT NULL COMMENT '身份证号',
`id_card_front_img_url` varchar(255) DEFAULT NULL COMMENT '身份证正面图URL',
`id_card_back_img_url` varchar(255) DEFAULT NULL COMMENT '身份证反面图URL',
`village_code` char(12) NOT NULL COMMENT '村级行政区划代码(GB/T 2260)',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '0-待审核, 1-已通过, 2-已拒绝',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_id_card_no` (`id_card_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='农户基本信息';
-- 产品信息表:聚焦农产品特性
CREATE TABLE `product_info` (
`id` bigint NOT NULL AUTO_INCREMENT,
`farmer_id` bigint NOT NULL COMMENT '所属农户ID',
`crop_name` varchar(100) NOT NULL COMMENT '作物名称',
`harvest_date` date NOT NULL COMMENT '采摘日期',
`shelf_life_days` int NOT NULL COMMENT '货架期(天)',
`actual_stock` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '实际库存(kg)',
`expiry_date` date GENERATED ALWAYS AS (DATE_ADD(`harvest_date`, INTERVAL `shelf_life_days` DAY)) STORED COMMENT '理论保质截止日',
PRIMARY KEY (`id`),
KEY `idx_farmer_id` (`farmer_id`),
KEY `idx_harvest_date` (`harvest_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='农产品信息';
-- 订单表:记录真实履约过程
CREATE TABLE `order_info` (
`id` bigint NOT NULL AUTO_INCREMENT,
`order_no` varchar(32) NOT NULL COMMENT '订单号(yyyyMMddHHmmssSSS+3位随机数)',
`buyer_id` bigint NOT NULL COMMENT '买家ID',
`farmer_id` bigint NOT NULL COMMENT '农户ID',
`product_id` bigint NOT NULL COMMENT '产品ID',
`status` varchar(20) NOT NULL DEFAULT 'WAITING_PICKUP' COMMENT '订单状态',
`pickup_time` datetime DEFAULT NULL COMMENT '农户接单时间',
`delivery_time` datetime DEFAULT NULL COMMENT '物流揽收时间',
`sign_time` datetime DEFAULT NULL COMMENT '买家签收时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`),
KEY `idx_status` (`status`),
KEY `idx_farmer_id` (`farmer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单信息';
三个设计亮点:
- expiry_date是生成列(GENERATED ALWAYS AS):MySQL 5.7+支持,自动根据harvest_date和shelf_life_days计算,不用程序层维护,数据绝对一致。
- 索引优化直指农业查询场景:product_info表建了idx_harvest_date索引,因为“查最近采摘的产品”是最高频操作;order_info表的idx_status索引,支撑“查所有待接单订单”这种后台管理需求。
- 字段命名拒绝通用化:不用create_time而用harvest_date,不用quantity而用actual_stock(强调“实际”库存,区别于电商的“可用库存”),这些细节让导师一眼看出你深入理解了领域。
4. 实操过程与核心环节实现:从环境搭建到全流程演示
4.1 环境搭建:三步走,告别“配环境到崩溃”
第一步:装基础环境(10分钟)
- JDK 1.8:去Oracle官网下载jdk-8u202-windows-x64.exe(别下新版本,SpringBoot 2.3.x对JDK 17支持不完善)
- MySQL 5.7:推荐用MySQL Installer(mysql-installer-community-5.7.31.0.msi),勾选“Developer Default”,一路下一步,记住安装时设置的root密码(比如123456)
- Maven 3.6.3:解压apache-maven-3.6.3-bin.zip,配置环境变量MAVEN_HOME和PATH
- Navicat Premium 15:破解版或试用版均可,用于导入SQL脚本
第二步:导入数据库(5分钟)
1. 打开Navicat,新建MySQL连接,主机填localhost,端口3306,用户名root,密码填你设的123456
2. 连接成功后,右键“连接名”→“新建数据库”,数据库名填agri_system,字符集选utf8mb4
3. 右键新创建的agri_system数据库→“运行SQL文件”,选择源码包里的jspmk37ae.sql,勾选“执行前提示”和“遇到错误继续”,点击“开始”
4. 导入完成后,在左侧表列表里能看到farmer_info、product_info等12张表,说明成功
第三步:启动后端(3分钟)
1. 用IDEA打开源码包根目录(含pom.xml的文件夹)
2. 等Maven自动导入依赖(右下角提示“Importing Maven project”完成)
3. 找到com.xxx.agri.AGriSystemApplication.java,右键→“Run ‘AGriSystemApplication.main()’”
4. 控制台出现Tomcat started on port(s): 8080 (http),说明后端启动成功
提示:如果启动报错
Access denied for user 'root'@'localhost',说明数据库密码不对。打开src/main/resources/application-dev.yml,修改spring.datasource.password为你实际的MySQL密码。
4.2 前端启动与联调:让页面“活”起来
开发联调模式(推荐给毕设学生)
1. 进入源码包里的webapp/dist目录(注意:不是src目录!)
2. 用VS Code打开该目录,安装插件“Live Server”
3. 右键index.html→“Open with Live Server”,浏览器自动打开http://127.0.0.1:5500/
4. 此时前端访问的是本地8081端口(前端开发服务器),后端是8080端口,需配置跨域。打开src/main/java/com/xxx/agri/config/WebMvcConfig.java,确认addCorsMappings方法已启用,允许http://127.0.0.1:5500来源。
生产部署模式(答辩演示用)
1. 进入前端源码目录(源码包里应该有frontend文件夹,或src/webapp)
2. 打开终端,执行:
bash npm install # 安装依赖 npm run build # 构建生产环境代码,生成dist目录
3. 将生成的dist目录整个拷贝到后端项目的src/main/resources/static/下(覆盖原有内容)
4. 重启后端应用,访问http://localhost:8080,此时前端静态文件由SpringBoot内置Tomcat直接提供,无需额外Web服务器,演示更稳定。
4.3 全流程演示视频实操指南:如何让答辩老师眼前一亮
配套的演示视频不是摆设,而是你的“答辩提词器”。我建议按这个顺序播放,并配合讲解:
视频1:农户注册与资质审核(3分钟)
- 播放张大叔用手机拍摄身份证正反面上传的过程(视频里能看到id_card_front_img_url字段被赋值为/upload/idcard/20231001_abc123.jpg)
- 讲解重点:“系统要求上传身份证,是为了后续对接政府‘新型职业农民’认证系统预留接口,目前先做基础校验”
- 演示后台审核:登录管理员账号,进入/admin/farmer/list,找到张大叔的申请,点击“通过”,状态变为已通过
视频2:产品发布与智能排序(2分钟)
- 播放张大叔填写“翠玉黄瓜”、“采摘日期2023-10-01”、“货架期3天”的过程
- 讲解重点:“货架期3天意味着系统会在10月4日开始对该产品做滞销预警,这是农业系统区别于电商的核心逻辑”
- 演示搜索:买家在首页搜索“黄瓜”,结果按harvest_date DESC排序,最新采摘的排第一
视频3:订单履约与预警联动(4分钟)
- 播放李阿姨下单→系统自动匹配张大叔→张大叔APP收到推送→张大叔点击“接单”→状态变PICKING_UP
- 讲解重点:“接单动作触发短信通知物流方,同时更新订单表的pickup_time字段,为后续时效分析提供数据”
- 演示预警:进入后台/admin/warning/expiring,看到“翠玉黄瓜库存200kg,剩余货架期1天”,点击“一键推送”,周边5个社区群收到特价信息
注意:答辩时不要只放视频!在视频暂停处,切换到数据库Navicat,现场执行SQL:
SELECT * FROM order_info WHERE status = 'DELIVERED' AND sign_time > DATE_SUB(NOW(), INTERVAL 1 DAY);
展示“昨天签收的订单”,证明系统真实运行。这种“视频+现场SQL验证”的组合,比单纯讲PPT有力十倍。
5. 常见问题与排查技巧实录:那些没人告诉你的坑
5.1 启动失败类问题速查表
| 问题现象 | 可能原因 | 排查命令/步骤 | 解决方案 |
|---|---|---|---|
后端启动报错:Failed to configure a DataSource | application-dev.yml里数据库连接配置错误 | 在IDEA中打开该文件,检查spring.datasource.url是否为jdbc:mysql://localhost:3306/agri_system?useSSL=false&serverTimezone=Asia/Shanghai | 修改URL,确保数据库名agri_system与Navicat里创建的一致;密码正确 |
前端页面空白,控制台报GET http://localhost:8080/api/login 404 | 前端请求路径未配置反向代理,或后端Controller路径写错 | 浏览器F12→Network,看请求URL;检查ProductController.java顶部是否有@RequestMapping("/api/product") | 确认所有Controller类都加了@RequestMapping("/api/*")前缀;开发时用跨域配置,生产时用Nginx反向代理 |
| 登录成功但无法进入后台,一直跳转回登录页 | JWT Token未正确存入localStorage,或拦截器未放行静态资源 | F12→Application→Storage→localStorage,看是否有token字段;检查JwtAuthenticationFilter.java的shouldNotFilter方法 | 确保前端登录成功后执行localStorage.setItem('token', response.data.token);拦截器里添加/static/**和/favicon.ico放行 |
5.2 业务逻辑类问题避坑指南
坑1:农户发布产品后,在买家端搜不到
- 原因:product_info表的status字段默认是0(草稿),未设为1(上架)
- 排查:Navicat执行SELECT * FROM product_info WHERE crop_name = '黄瓜';,看status值
- 修复:在ProductController.addProduct()方法末尾,加上product.setStatus(1);,或在ProductMapper.xml的<insert>语句里写status = 1
坑2:滞销预警没触发,明明库存很多
- 原因:expiry_date是生成列,但MySQL 5.7默认不开启innodb_file_per_table,导致生成列索引失效
- 排查:执行SHOW VARIABLES LIKE 'innodb_file_per_table';,返回OFF
- 修复:在MySQL配置文件my.ini里添加innodb_file_per_table=ON,重启MySQL服务
坑3:短信发不出,控制台报Invalid AccessKeyId
- 原因:application-dev.yml里的阿里云AccessKey泄露,被别人盗用导致额度用尽
- 排查:登录阿里云控制台→短信服务→用量查询,看今日发送量是否为0
- 修复:立即在阿里云控制台创建新AccessKey,替换配置文件里的aliyun.sms.access-key-id和access-key-secret;为安全起见,把application-dev.yml加入.gitignore,避免提交到Git
5.3 毕设答辩高频问题应答锦囊
Q:为什么用MySQL不用MongoDB?农产品数据不是非结构化吗?
A:农产品核心数据(农户信息、产品规格、订单状态)高度结构化,MySQL的ACID事务保障库存扣减的准确性至关重要。MongoDB适合存“农户上传的种植日记图片”这类附件,但本系统用/upload/目录存文件,数据库只存URL,更轻量可靠。
Q:JWT Token存localStorage有XSS风险,为什么不存HttpOnly Cookie?
A:毕设场景下,XSS攻击概率极低,且存Cookie需后端配合withCredentials,增加跨域复杂度。我们已在所有输入框做了XSS过滤(StringEscapeUtils.escapeHtml4()),并限制Token有效期为2小时,风险可控。
Q:系统怎么保证农户发布的“有机认证”是真的?
A:当前版本是农户自行勾选,作为基础功能。扩展方案是:对接国家认监委“中国有机产品认证信息系统”,在farmer_info表加organic_cert_no字段,调用其API验证证书真伪。这正是我建议的毕设“创新点”方向——在现有系统上叠加一个政府数据接口。
最后分享一个小技巧:答辩前夜,务必用mvn clean package -Dmaven.test.skip=true打包一次,生成target/agri-system-1.0.jar,把它和jspmk37ae.sql一起拷贝到U盘。答辩现场,老师让你现场演示,你就双击U盘里的start.bat(内容为java -jar agri-system-1.0.jar),5秒启动,打开浏览器输入localhost:8080,流畅演示。这种“说干就干”的执行力,比讲一百页PPT都管用。毕竟,毕设的本质不是创造新世界,而是把一个真实问题,用扎实的技术,稳稳地解决掉。
简介:直接拿来就能跑的农产品供销管理系统,前后端分离结构,前端用Vue搭配Element UI和Layui做界面,响应式适配PC端;后端基于SpringBoot,集成MyBatis和Spring MVC,用JWT实现Token登录验证。功能覆盖农户信息维护、农产品上架发布、买家下单、订单状态跟踪、库存实时统计、供需匹配对接等真实业务场景。数据库脚本(jspmk37ae.sql)兼容MySQL 5.7和8.0,用Navicat一键导入即可。开发环境明确:JDK 1.8及以上、Windows 10或更高系统、Maven构建工具,项目目录结构规范,含controller/service/mapper/entity分层代码,关键逻辑均有中文注释。配套多个演示视频,从用户注册登录、农户发布产品、买家下单到后台审核发货,每步操作都有对应录屏。适合计算机相关专业本科生做毕业设计,源码可直接部署运行,支持修改字段、替换页面样式、扩展API接口等二次开发,避免重复造轮子,满足高校对功能完整性、技术栈合理性及现场演示可行性的基本要求。


被折叠的 条评论
为什么被折叠?



