ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring Boot+EasyUI+MySQL:农业物资管理系统开发实战

Spring Boot+EasyUI+MySQL:农业物资管理系统开发实战 做农业物资管理系统这个项目之前我其实已经用传统 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, statusmaterial_category物资类别id, category_name, remarkmaterial_info物资档案id, category_id, material_name, spec, unit, warn_stocksupplier供应商id, supplier_name, contact, phone, addressstock_in入库单id, material_id, supplier_id, quantity, unit_price, total_amount, in_time, operatorstock_out出库单id, material_id, quantity, recipient, purpose, out_time, operatormaterial_stock库存表id, material_id, stock_quantity先说 sys_user 表。password 字段我用的是 MD5 加盐加密存储虽然现在有更强的 BCrypt但很多老项目为了方便对接还在用 MD5我实操中更推荐直接上 BCryptSpring 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 里开启逻辑删除配置后所有查询会自动过滤 deleted1 的数据写起来几乎无感。关于库存联动入库和出库都会影响 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 17Maven3.6.3 或 3.9.x3.8 对镜像配置有更严格的校验注意 settings.xmlMySQL8.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 idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://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 groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- MyBatis-Plus 增强 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency !-- MySQL 驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.28/version /dependency !-- Lombok 简化实体类 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- 常用工具类 -- dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.18/version /dependency /dependencies用 MyBatis-Plus 而不是原生 MyBatis我是认真对比过的。MyBatis-Plus 提供现成的 BaseMapper 和 IService单表 CRUD 几乎不用写 SQLUpdateById、SelectList 这些方法直接调用就行。这对于本项目的业务类型大量单表操作非常友好开发效率提升巨大。如果你的业务需要多表 join 复杂查询那还是得老老实实写 XML 里的 SQLMyBatis-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?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue 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 这个连接串我多说几句。useSSLfalse解决的是 MySQL 8.0 默认开启 SSL 导致的警告日志serverTimezoneAsia/Shanghai解决的是时区问题不设置这个参数数据库时间比本地时间早 8 个小时报表统计会全部错位allowPublicKeyRetrievaltrue解决的是 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 langzh head meta charsetUTF-8 link relstylesheet href/js/easyui/themes/default/easyui.css link relstylesheet 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 iddg title物资列表 classeasyui-datagrid styleheight: 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 LambdaQueryWrapperMaterialStock() .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 updateMyBatis-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 里少了allowPublicKeyRetrievaltrue如果报The server time zone value Öйú±ê׼ʱ¼ä那就是少了serverTimezoneAsia/Shanghai同时控制台还全是乱码。这两个报错我几乎每次搭新项目都能遇到把 url 里的参数对齐基本上能解决 90% 的 MySQL 连接问题。另外驱动类名也要注意MySQL 5.7 用的是com.mysql.jdbc.DriverMySQL 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 项目里是老生常谈。我总结的排查链路是数据库连接串里characterEncodingutf8有没有加数据库本身的编码和表的排序规则是不是 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 展示图表这个系统的完整度会立刻上一个台阶。
返回列表