☰
Spring Boot+EasyUI+MySQL:农业物资管理系统开发实战
2026/10/1 3:21:32 网站建设 项目流程

做农业物资管理系统这个项目之前,我其实已经用传统 SSM 写过好几个类似的管理后台,但每次都被繁琐的 XML 配置折磨得够呛。所以这次基于 javaweb 和 mysql 的 springboot 农业物资管理系统,我直接采用了 java + springboot + easyui + html + maven + mysql 这套组合,把整个开发体验和最终效果都拉高了一个档次。说白了,这就是一套典型的仓储进销存后台,只不过业务场景聚焦在农资产品上——农药、化肥、种子、农膜这一类商品的入库、出库、库存盘点和供应商管理。适合正在做毕设、刚入职需要快速上手企业管理系统开发,或者想找一个完整 javaweb 项目练手的朋友参考。

这套系统的核心价值在于:Spring Boot 解决了传统 JavaWeb 项目配置繁琐、启动慢的问题,Maven 统一管理了依赖版本,MySQL 提供稳定的数据存储,而 EasyUI 则是我在后台管理系统里用过最顺手的 UI 方案之一——表格、弹窗、表单校验基本都封装好了,不用自己手搓一套复杂的前端交互。这篇博客我会从项目整体的设计思路、数据库表结构、实操搭建过程到常见的坑,按我实际开发的顺序完整复盘一遍,每一步都会附带可以直接落地的配置和代码。

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

1.1 为什么是 Spring Boot + EasyUI 这套组合

先聊选型。我最早考虑过 Vue + Element UI 做前后端分离,后来放弃了,原因很实际:农业物资管理这类项目,核心的使用场景是仓库管理员、采购员,他们需要的是登录后快速打开页面、表格里查数据、点按钮弹窗录入这种传统操作模式,而不是复杂的单页应用交互。EasyUI 在这一点上优势特别明显,它本身是一套基于 jQuery 的 UI 组件库,自带 datagrid 数据表格、dialog 弹窗、form 表单、tree 树形结构这些后台管理系统的高频组件,写起来几乎就是“填配置”,开发速度非常快。

后端选 Spring Boot 没什么悬念。它内嵌了 Tomcat,不用再单独部署 war 包到外部容器,java -jar 就能直接跑起来;自动配置机制也帮我省掉了一大堆 XML Bean 定义。对比我早年写 SSM 项目时的配置量,Spring Boot 至少节省了 60% 的搭建时间。数据库用 MySQL 8.0,免费、稳定、资料多,学生和企业内部项目都够用。Maven 在这里承担的作用是依赖管理和构建打包,spring-boot-starter-web、mybatis-plus、mysql-connector-java 这些关键库的版本都由 Maven 统一约束,避免“本地能跑、换台电脑就编译不过”的尴尬。

有人会问,为什么不引入 Redis、RabbitMQ 这些中间件?我的看法是:不要为了技术而技术。农业物资系统的业务模型是典型的小型 CRUD + 事务,并发量不高,数据量也不大到需要缓存兜底。硬上微服务或者消息队列,只会把部署成本和维护难度抬起来。把 Spring Boot、EasyUI、MySQL 这三样吃透,配合 Maven 做工程化管理,已经能覆盖 90% 的中小企业后台管理场景。

1.2 农业物资业务的模块划分:从业务痛点出发

技术选型定了之后,最关键的是把业务模块梳理清楚。农业物资管理和普通进销存有个明显的区别:物资具有季节性、专业性和批次敏感性。比如化肥分复合肥、尿素,不同品牌不同含量;种子要按品种、生产日期、保质期管理;农药还要关注生产批号。所以我把系统拆成了六个核心模块:

  • 用户登录与权限模块:管理人员账号,区分管理员和普通操作员,登录后才能访问系统。
  • 物资类别与档案模块:先维护物资分类,再维护具体的物资信息(名称、规格、单位、预警库存值)。
  • 供应商管理模块:管理供应商档案,包括联系人、电话、地址,方便采购时选择。
  • 采购入库模块:录入入库单,选择物资和供应商,填写数量、单价,自动生成本入库记录。
  • 出库领用模块:对应出库单,记录领取人、领取物资、数量、用途,出库时自动扣减库存。
  • 库存管理与预警模块:实时展示每种物资的当前库存,低于预警值时在列表中高亮提示。

模块拆分的原则我总结成一句话:让每个角色在系统里只做自己关心的事。比如库管员打开首页能看到所有物资库存和预警,采购员主要用入库单和供应商模块,管理员负责维护用户和基础数据。模块之间通过 MySQL 的外键关系和 Service 层的事务操作关联起来,没有刻意做微服务拆分,因为这类系统单体架构就是最优解,数据一致性更好控制,排查问题也更简单。

这套模块设计跑下来,最直接的收益就是业务逻辑清晰,到了写代码阶段,每个 Controller、Service、Mapper 基本都能和模块一一对应。我实际编码的时候,从建表到接口跑通,前后只用了大概两周时间,其中很大一部分效率提升就来自模块边界划得清楚,没有出现“这个逻辑该放哪个 Service”的纠结。

2. 核心功能与数据库设计:表结构才是系统的地基

2.1 核心表结构解析:从 user 到 stock 的完整链路

数据库设计是所有管理系统的地基,表结构没想清楚,后面写代码就是给自己挖坑。这套系统的核心表我列在下面,每一张表都对应一个独立的业务概念,字段设计也经过了反复推敲。

表名用途关键字段
sys_user系统用户id, username, password, real_name, role, status
material_category物资类别id, category_name, remark
material_info物资档案id, category_id, material_name, spec, unit, warn_stock
supplier供应商id, supplier_name, contact, phone, address
stock_in入库单id, material_id, supplier_id, quantity, unit_price, total_amount, in_time, operator
stock_out出库单id, material_id, quantity, recipient, purpose, out_time, operator
material_stock库存表id, material_id, stock_quantity

先说 sys_user 表。password 字段我用的是 MD5 加盐加密存储,虽然现在有更强的 BCrypt,但很多老项目为了方便对接还在用 MD5,我实操中更推荐直接上 BCrypt,Spring Security 里有现成的 BCryptPasswordEncoder,安全性高一个档次。role 字段区分管理员和操作员,管理员可以管理用户,操作员只能操作日常业务,这个简单的分级在权限控制里已经能覆盖大部分需求。

material_info 表里的 warn_stock 是预警库存值,字段类型选 int 或者 decimal 都可以,具体看物资是不是可能有小数单位。这里有个我踩过的坑:如果物资单位是“瓶”“袋”这类整数单位,用 int 没问题;但如果涉及“公斤”“升”这种需要精确到小数点后两位的,就必须用 decimal(10,2),否则前端表格会出现 4.999999 这种浮点数误差。

material_stock 是最核心的表,设计上我让它只保存当前库存数量,不记录历史流水。为什么这么设计?因为流水数据量大,而且入库表、出库表本身就是明细账,库存表只做“当前状态”的冗余展示就好——每次出入库时同步更新 material_stock 的 stock_quantity,查询当前库存时直接查这张表,速度极快,不需要连表 join 计算。这是典型的空间换时间思路。

2.2 数据库设计的关键决策:逻辑删除、库存联动与索引

关于逻辑删除,我给所有业务表都加了 deleted 字段,默认 0,删除数据时置为 1,而不是物理 DELETE。原因很简单:物资和供应商的入库记录可能涉及财务核算,如果误删或者需要追溯历史,物理删除就彻底找不回来了。MyBatis-Plus 里开启逻辑删除配置后,所有查询会自动过滤 deleted=1 的数据,写起来几乎无感。

关于库存联动,入库和出库都会影响 material_stock 表。最直接的实现方式是在入库/出库的 Service 方法里,先写明细单,再更新库存表。这里必须强调事务:如果插入出库单成功但更新库存失败,数据就不一致了。我是用 @Transactional 把整个操作包在同一个事务里,一旦任何一个步骤抛异常,全部回滚。这个细节如果漏掉,系统上线后一定会出大问题,而且非常难排查,因为你看到的出库单和实际库存永远对不上。

关于索引,我主要给三个字段加了索引:stock_in 表的 material_id、stock_out 表的 material_id、material_stock 表的 material_id。为什么就这三个?因为项目里最频繁的查询就是“按物资查出入库记录”“按物资查当前库存”,这些字段都是高频 where 条件。其他字段比如入库时间,数据量不大时加索引反而浪费空间和维护成本。索引不是越多越好,这个度需要根据实际查询场景来把握。

3. 实操过程与核心环节实现

3.1 环境准备与版本搭配:先搞定这套开发组合

开发环境我用的版本组合是:JDK 1.8 + Maven 3.6.3 + MySQL 8.0.28 + IDEA 2023.2 + Spring Boot 2.7.18。具体版本选择我做了个对照表,方便你根据自己的情况调整:

组件推荐版本注意事项
JDK1.8 或 11Spring Boot 2.x 用 JDK 8 最稳,如果要用 3.x 必须切 JDK 17
Maven3.6.3 或 3.9.x3.8+ 对镜像配置有更严格的校验,注意 settings.xml
MySQL8.0 或 5.78.0 驱动类名和连接 URL 与 5.7 不同,别搞混
Spring Boot2.7.x2.7 是 2.x 的最后一个稳定版本,比 3.x 兼容性更好,社区资料多
IDEA任意较新版本建议用 2022.1 以上,对 Maven 和 Spring Boot 的支持更完善

这里要特别提醒一个坑:如果你因为版本太高装了 Spring Boot 3.x,那 JDK 至少得 17,同时 javax.* 包名全部要换成 jakarta.*,很多老教程里的代码直接照抄会编译报错。我建议第一次做这个项目的人老老实实用 Spring Boot 2.7.x + JDK 8,代码和教程的兼容性都是最稳的。

Maven 安装好之后,第一件事就是修改 settings.xml 加阿里云镜像,否则下载依赖的速度可能是地狱级。我贴一段我常用的镜像配置:

<mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>

加上这个配置之后,mvn clean install 的速度提升不是一点半点,实测能从十几分钟降到一两分钟。IDEA 里导入 Maven 工程时,记得在 Settings -> Maven 里把 User settings file 指向你自己的 settings.xml,否则 IDE 用的是内置默认配置,改了不生效。

3.2 Maven 工程搭建:pom.xml 里这些依赖一个都不能少

创建工程我推荐用 IDEA 的 Spring Initializr,直接选好 Spring Boot 版本和依赖,生成出来的工程结构就是标准的。核心的 pom.xml 依赖我列在下面,这些都是这套系统跑起来的必需品:

<dependencies> <!-- Spring Boot Web 核心 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis-Plus 增强 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3</version> </dependency> <!-- MySQL 驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> <!-- Lombok 简化实体类 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- 常用工具类 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.18</version> </dependency> </dependencies>

用 MyBatis-Plus 而不是原生 MyBatis,我是认真对比过的。MyBatis-Plus 提供现成的 BaseMapper 和 IService,单表 CRUD 几乎不用写 SQL,UpdateById、SelectList 这些方法直接调用就行。这对于本项目的业务类型(大量单表操作)非常友好,开发效率提升巨大。如果你的业务需要多表 join 复杂查询,那还是得老老实实写 XML 里的 SQL,MyBatis-Plus 也不影响这一点,两者可以共存。

Lombok 一定记得在 IDEA 里装 Lombok 插件,否则 @Data 注解不会生效,实体类会全报红。Hutool 是我个人非常喜欢的工具库,日期处理、字符串操作、IdUtil 生成分布式 ID 都有现成方法,比自己去写那些工具函数省事得多。

3.3 application.yml 配置:数据源和 MyBatis 的这些参数

工程的灵魂在配置文件里。Spring Boot 的 application.yml 我写过很多次,每次都有几个参数容易记错,尤其是 MySQL 8.0 的连接串。下面是我项目里实际用的配置,直接复制改密码即可:

server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/agri_material?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: root password: 123456 mybatis-plus: mapper-locations: classpath*:/mappers/**/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0

关于 url 这个连接串,我多说几句。useSSL=false解决的是 MySQL 8.0 默认开启 SSL 导致的警告日志;serverTimezone=Asia/Shanghai解决的是时区问题,不设置这个参数,数据库时间比本地时间早 8 个小时,报表统计会全部错位;allowPublicKeyRetrieval=true解决的是 MySQL 8.0 使用 caching_sha2_password 认证方式时,客户端可能报 Public Key Retrieval 不允许的问题。这三个参数是我折腾过很久才总结齐的,缺一个都可能跑不起来。

map-underscore-to-camel-case: true这个配置非常实用。数据库字段是material_name、unit_price这种下划线风格,Java 实体类是materialName、unitPrice这种驼峰风格,开启这个选项后 MyBatis 自动做映射,不用手写一大堆 resultMap。实际操作中,只要保持“数据库下划线、Java 驼峰”的命名约定,整个项目的映射代码可以减少 70%。

3.4 搭建 EasyUI 页面框架:从静态资源到数据表格

EasyUI 的整合方式和前后端分离项目不太一样,它更接近传统 JavaWeb 的思路——HTML 页面放静态资源目录,通过 Ajax 请求后端 JSON 接口,再用 EasyUI 组件渲染。我把 easyui 相关的 js、css 放在src/main/resources/static/js/easyui目录下,页面里直接引用即可。

先看最简单的列表页,用 datagrid 展示物资列表。这段代码至关重要,因为整个系统 90% 的页面都是这个结构:

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="/js/easyui/themes/default/easyui.css"> <link rel="stylesheet" href="/js/easyui/themes/icon.css"> <script src="/js/jquery.min.js"></script> <script src="/js/easyui/jquery.easyui.min.js"></script> <script src="/js/easyui/locale/easyui-lang-zh_CN.js"></script> </head> <body> <table id="dg" title="物资列表" class="easyui-datagrid" style="height: 600px" >@Service public class StockInServiceImpl implements StockInService { @Autowired private StockInMapper stockInMapper; @Autowired private MaterialStockMapper materialStockMapper; @Transactional(rollbackFor = Exception.class) public void addStockIn(StockIn stockIn) { // 1. 保存入库单 stockInMapper.insert(stockIn); // 2. 查询当前库存 MaterialStock stock = materialStockMapper.selectOne( new LambdaQueryWrapper<MaterialStock>() .eq(MaterialStock::getMaterialId, stockIn.getMaterialId()) ); // 3. 更新库存数量 if (stock == null) { // 首次入库,直接创建库存记录 stock = new MaterialStock(); stock.setMaterialId(stockIn.getMaterialId()); stock.setStockQuantity(stockIn.getQuantity()); materialStockMapper.insert(stock); } else { // 已有库存,累加数量 stock.setStockQuantity(stock.getStockQuantity() + stockIn.getQuantity()); materialStockMapper.updateById(stock); } } }

@Transactional(rollbackFor = Exception.class) 这个注解是核心。rollbackFor 设置了任何异常都回滚,不光是 RuntimeException。我之前踩过坑:默认情况下 Spring 只对运行时异常回滚,如果代码里抛了一个受检异常,事务照样提交,数据就错了。现在所有写操作我都统一用 rollbackFor = Exception.class,彻底杜绝这个问题。

出库时还要多一个检查步骤:扣减库存之前必须先判断当前库存是否足够,不够就直接抛异常拒绝操作。这样才能避免出现负数库存这种反常识的数据。另外有一点要注意的是并发问题:如果两个操作员同时给同一个物资出库,理论上会出现超扣。这个问题在低并发场景下不明显,但如果想做得更严谨,可以用 MySQL 的悲观锁在查询库存时加上for update(MyBatis-Plus 里通过 selectForUpdate 实现)。我实际开发中考虑到农业物资系统并发量不高,用事务回滚已经够用,就没上锁,但你在设计时最好评估一下自己的业务场景。

4. 常见问题与排查技巧实录

4.1 Maven 依赖下载慢、依赖报红怎么办

这估计是新手遇到最多的问题。第一选择是改阿里云镜像,前面已经给过配置代码。第二是IDEA 里 Maven 工具窗口的刷新按钮点到烦,一定要学会用mvn clean install -DskipTests命令行去构建,控制台会显示具体是哪个依赖拉不下来。第三,如果改了镜像还是报红,检查仓库里是不是留下了损坏的 jar 包——把本地仓库目录/.lastUpdated结尾的文件删除,重新拉取就好了。

还有一个容易忽略的点:IDEA 里 Maven 的 JDK for importer 设置。有时候本地装的是 JDK 8,但 IDEA 默认给 Maven importer 配上 JDK 17,编译时各种invalid source release报错。我建议在 Settings -> Build Tools -> Maven -> JDK for importer 里明确选成本地 JDK 8,就不会有这种幺蛾子。

4.2 MySQL 连接报错:SSL、时区、驱动类名三连坑

MySQL 8.0 的连接问题我已经在上文说过 URL 的完整参数,这里再补一个常见场景:如果你启动项目时报Public Key Retrieval is not allowed,那是在 url 里少了allowPublicKeyRetrieval=true;如果报The server time zone value 'Öйú±ê׼ʱ¼ä',那就是少了serverTimezone=Asia/Shanghai,同时控制台还全是乱码。这两个报错我几乎每次搭新项目都能遇到,把 url 里的参数对齐,基本上能解决 90% 的 MySQL 连接问题。

另外,驱动类名也要注意:MySQL 5.7 用的是com.mysql.jdbc.Driver,MySQL 8.0 是com.mysql.cj.jdbc.Driver,多了一个cj。如果驱动类写错了,启动时直接 ClassNotFound。我建议直接统一用 8.0 驱动,即使你连的是 5.7 数据库也能兼容。

4.3 EasyUI 表格加载不出数据:先检查 JSON 格式

EasyUI 表格不显示数据,大部分情况下不是前端代码的问题,而是后端返回的 JSON 格式不对。我整理了一张速查表,方便你照着一项项排查:

序号排查项正确格式
1返回结构必须是 { "total": 总条数, "rows": [{}] }
2字段名大小写与 easyui 里 field 属性严格对应
3日期类型建议后端格式化为 yyyy-MM-dd HH:mm:ss 字符串
4空列表rows 里不能直接返回 null,要返回 []
5接口响应码必须是 200,不是 200 时 datagrid 直接不渲染

第三点是很多人忽略的:如果实体类里有一个 Date 字段,序列化成 JSON 时默认输出是一长串时间戳,EasyUI 会识别不了。我的做法是在实体类日期字段上加上@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")注解,保证输出可读的字符串。另外,如果多个资源路径写错导致 404,前端不会报错,只是表格一直空白,这种隐蔽的问题最耽误时间,排查时优先看浏览器 Network 里的请求状态码。

4.4 端口占用与启动失败:快速定位和解决

Spring Boot 启动失败最常见的原因就是端口被占用。IDEA 控制台会报Port 8080 was already in use,解决方案是找到占用进程并结束它。Windows 下我用两个命令搞定,Linux/Mac 也类似:

# 查看8080端口被谁占用 netstat -ano | findstr 8080 # 结束对应进程,PID换成查到的值 taskkill /PID 端口对应的PID /F

还有一种情况是启动时提示找不到主类,通常是因为 IDEA 的 Artifacts 配置问题。最简单的处理方式是 Maven 工具窗口里先clean再package,重新构建一遍,基本能解决 90% 的启动类相关诡异问题。不建议用 IDEA 的缓存清理那个功能,经常清了之后要重新索引半天,反而更麻烦。

4.5 中文乱码:一个配置解决前后端所有乱码

中文乱码问题在 JavaWeb 项目里是老生常谈。我总结的排查链路是:数据库连接串里characterEncoding=utf8有没有加?数据库本身的编码和表的排序规则是不是 utf8mb4?后端响应有没有设置 Content-Type 里带 charset?对于 Spring Boot 项目,前端传参乱码通常不需要额外配置(内置了 UTF-8 过滤器),但数据库侧如果没有设置 utf8mb4,就会出现“插入正常、查询出来是问号”的诡异现象。

我建库时统一用的是CREATE DATABASE agri_material DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;,表结构设置跟随库。utf8mb4 比 utf8 多了对 emoji 表情的支持,虽然农资系统里不会存表情,但现在普遍推荐这个编码,防止未来扩展时踩坑。

个人实操体会

项目收尾之后,我最大的感受是:技术栈老不代表落后,适合业务场景的就是最好的。Spring Boot + EasyUI + MySQL + Maven 这套组合,在农业物资管理这种以表单、表格、弹窗为核心交互形态的业务系统里,开发效率和可维护性都非常不错。EasyUI 虽然不像 Vue 那样炫酷,但胜在稳定、文档全、对低配置 PC 友好——一线的仓库电脑往往配置不高,传统组件反而比重型前端框架更实用。

最后分享一个小技巧:做这类管理系统时,先把所有列表页和后端接口的 JSON 格式完全对齐,再开始写表单和弹窗逻辑,后面的开发速度快到飞起。后续如果你想扩展,可以在这个基础上往两个方向深入:一是引入 Spring Security 或者 JWT 做更精细的权限控制;二是增加简单的报表统计功能,比如按月份统计每种物资的出入库汇总,用 ECharts 展示图表,这个系统的完整度会立刻上一个台阶。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询