SpringBoot+MySQL实战:农产品库存管理系统毕业设计全流程解析
如果你是一名计算机专业的学生正在为毕业设计寻找一个“既有技术含量又能跑通演示”的SpringBoot项目那么这篇文章就是为你准备的。毕业设计不是简单的代码堆砌它需要你展示对技术栈的理解、对业务逻辑的梳理以及一个能稳定运行、界面清晰、功能完整的系统。然而很多同学卡在了第一步找不到一个结构清晰、文档完整、能从头到尾跑起来的参考项目。今天我们就以“农产品库存管理系统”这个典型的毕设选题为例进行一次深度拆解。这不仅仅是一个项目演示录像的复现更是一次从零开始的SpringBootMySQL实战指南。我们将重点解决三个核心问题第一如何快速搭建一个结构规范的SpringBoot项目骨架第二如何设计一个符合实际业务农产品库存的数据库与核心功能第三如何从前端到后端完整实现增删改查并打包部署。读完本文你将获得一个可直接用于毕设的、模块清晰的Java Web项目实现思路与关键代码并能理解其中每个技术选型背后的“为什么”从而真正掌握如何构建一个企业级应用雏形。1. 为什么“农产品库存管理”是绝佳的SpringBoot毕设选题在选择毕业设计题目时你需要平衡“技术深度”、“业务复杂度”和“可实现性”。“库存管理系统”是一个经典方向而将其限定在“农产品”领域则瞬间赋予了项目独特的业务场景和挑战这恰恰是答辩时的加分项。1.1 技术栈匹配度高易于展示综合能力SpringBoot MySQL (Thymeleaf/前后端分离) 是Java Web开发的黄金组合。这个技术栈足够主流和成熟能让你系统地展示从MVC分层、ORM映射MyBatis/MyBatis-Plus/JPA到事务管理、RESTful API设计等一系列核心技能。它不像微服务或大数据项目那样前期搭建复杂能让你把精力集中在业务逻辑实现上。1.2 业务场景具体需求分析有抓手“农产品”库存有其特殊性商品有品类蔬菜、水果、粮油、有批次关联生产日期、保质期、有损耗率、可能需要冷链管理。这些具体的业务约束让你在需求分析和数据库设计时有的放矢避免了泛泛而谈的“商品管理”。你可以设计“保质期预警”、“库存周转率统计”等特色功能体现你对业务的理解。1.3 功能模块清晰易于扩展和演示一个标准的库存管理系统包含用户权限管理、农产品分类管理、供应商管理、入库管理、出库管理、库存盘点、报表统计等模块。模块之间耦合度低功能边界清晰你可以分阶段实现最终集成。在答辩演示时你可以流畅地走完“新增一个土豆品类 - 从某供应商入库100斤 - 销售出库30斤 - 查看库存报表”的完整业务流程逻辑非常直观。1.4 面临的实际挑战与解决方案这个项目也会遇到典型问题而这正是你展示问题解决能力的机会并发与数据一致性多人同时操作同一农产品的库存时如何保证数据准确这引出了数据库事务和乐观锁如使用version字段的讨论。复杂查询与性能如何高效查询“还有3天过期的所有农产品”这需要合理的数据库索引设计和MyBatis动态SQL的应用。前端体验是使用传统的服务端渲染模板如Thymeleaf快速搭建还是采用前后端分离Vue SpringBoot展现更现代的技术架构两种选择各有优劣取决于你的技术侧重点。接下来我们将抛开空洞的理论直接进入实战环节一步步构建这个系统。2. 项目核心技术栈与架构设计在动手编码前明确技术选型和架构是避免后期混乱的关键。本项目我们采用一个平衡了学习曲线和现代性的技术组合。2.1 后端技术栈核心框架Spring Boot 2.7.x (选择LTS版本稳定优先)数据层ORM框架MyBatis-Plus。它是对MyBatis的增强提供了通用的Mapper和Service能极大减少单表CRUD的代码量让你更专注于业务逻辑。数据库MySQL 8.0。需要掌握基本的DDL建表、DML增删改查以及事务控制。Web层Spring MVC。处理HTTP请求、响应、参数绑定、数据验证等。模板引擎可选Thymeleaf。如果你选择服务端渲染模式用于将后端数据渲染成HTML页面。本文为简化演示后端将主要提供RESTful API。依赖管理Maven。管理项目依赖统一版本。其他工具Lombok通过注解简化Java Bean的Getter/Setter、构造方法等代码。Hutool国产工具库提供丰富的工具方法如日期处理、加密解密等。PageHelper方便地进行物理分页。2.2 前端技术栈模拟前后端分离为了更贴近现代开发方式我们假设前端由Vue等框架独立开发后端仅提供API。在本文的代码演示中我们将使用Postman或Swagger来测试API并给出清晰的JSON请求/响应格式。如果你需要快速出一个带界面的演示可以在后续集成一个简单的Thymeleaf页面。2.3 项目分层架构MVC增强版一个清晰的分层有助于代码维护和团队协作。我们采用以下结构src/main/java/com/agri/inventory/ ├── controller/ # 控制层接收请求调用服务返回结果 ├── service/ # 业务逻辑层核心业务处理 │ └── impl/ # 业务逻辑实现类 ├── mapper/ # 数据访问层MyBatis Mapper接口 ├── entity/ # 实体层与数据库表一一对应 ├── dto/ # 数据传输对象用于前后端交互 ├── vo/ # 视图对象用于封装返回给前端的数据 ├── common/ # 通用组件如统一响应封装、异常处理、常量 └── config/ # 配置类如MyBatis-Plus配置、Swagger配置这种分层确保了单一职责Controller只负责路由和参数校验Service处理业务规则Mapper只做数据持久化。3. 开发环境准备与项目初始化“工欲善其事必先利其器”。一个顺畅的环境是成功的第一步。3.1 必备软件安装JDK安装JDK 8或11推荐11并配置好JAVA_HOME环境变量。Maven安装Maven 3.6配置好仓库镜像推荐阿里云镜像加速依赖下载。MySQL安装MySQL 8.0记住root密码。建议使用图形化工具如Navicat或MySQL Workbench方便操作。IDEIntelliJ IDEA首选或 Eclipse。IDEA对Spring Boot支持极佳。API测试工具Postman或Insomnia用于测试后端接口。3.2 使用Spring Initializr快速初始化项目这是最规范的方式。访问 start.spring.io 或直接在IDEA中创建。Project: Maven ProjectLanguage: JavaSpring Boot: 2.7.x (选择一个稳定版本)Project Metadata:Group:com.agriArtifact:inventory-managementName:inventory-managementPackage name:com.agri.inventoryDependencies: 添加以下依赖Spring WebMySQL DriverMyBatis FrameworkLombok点击“Generate”下载项目压缩包解压后用IDEA打开。3.3 补充pom.xml依赖在项目根目录的pom.xml中我们需要添加MyBatis-Plus等关键依赖。!-- 文件pom.xml -- ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd !-- ... 其他父项目、属性等配置 ... -- dependencies !-- Spring Boot 基础依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency !-- 数据库相关 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version !-- 请使用最新稳定版 -- /dependency !-- 工具类 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.16/version !-- 请使用最新稳定版 -- /dependency !-- 分页插件 -- dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version1.4.6/version /dependency !-- API文档生成 -- dependency groupIdio.springfox/groupId artifactIdspringfox-boot-starter/artifactId version3.0.0/version /dependency /dependencies !-- ... 其他配置 ... -- /project3.4 配置数据库连接在src/main/resources/application.yml中配置数据库和MyBatis-Plus。# 文件src/main/resources/application.yml server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/agri_inventory_db?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/Shanghai username: root password: your_password # 替换为你的MySQL密码 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL开发时方便调试 global-config: db-config: id-type: auto # 主键策略数据库自增 logic-delete-field: isDeleted # 全局逻辑删除字段名如果启用 logic-delete-value: 1 # 逻辑已删除值 logic-not-delete-value: 0 # 逻辑未删除值 # PageHelper分页插件配置 pagehelper: helper-dialect: mysql reasonable: true support-methods-arguments: true4. 数据库设计与核心表结构数据库设计是系统的基石。围绕农产品库存管理我们设计以下核心表4.1 数据库ER图核心思路农产品分类表 (product_category)树状结构支持多级分类如蔬菜-叶菜类-菠菜。农产品信息表 (product)存储具体农产品的基本信息关联分类和供应商。供应商表 (supplier)管理农产品来源。仓库表 (warehouse)可扩展为多仓库管理。库存流水表 (inventory_transaction)核心表。记录每一次入库、出库、盘点的明细通过transaction_type字段区分操作类型。这是实现库存实时计算和追溯的基础。用户表 (sys_user)系统用户用于权限控制简化版可先做登录验证。4.2 核心表SQL脚本以下是product农产品信息和inventory_transaction库存流水两个关键表的建表语句。-- 文件database_schema.sql -- 创建数据库 CREATE DATABASE IF NOT EXISTS agri_inventory_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE agri_inventory_db; -- 农产品信息表 CREATE TABLE product ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, product_code varchar(64) NOT NULL COMMENT 农产品编码唯一, product_name varchar(128) NOT NULL COMMENT 农产品名称, category_id bigint(20) NOT NULL COMMENT 分类ID, supplier_id bigint(20) DEFAULT NULL COMMENT 供应商ID, unit varchar(20) DEFAULT 斤 COMMENT 计量单位斤、公斤、个, unit_price decimal(10,2) DEFAULT 0.00 COMMENT 参考单价, shelf_life_days int(11) DEFAULT NULL COMMENT 保质期天, description text COMMENT 描述, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, is_deleted tinyint(1) DEFAULT 0 COMMENT 逻辑删除标志0-未删除1-已删除, PRIMARY KEY (id), UNIQUE KEY uk_product_code (product_code), KEY idx_category_id (category_id), KEY idx_supplier_id (supplier_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT农产品信息表; -- 库存流水表核心 CREATE TABLE inventory_transaction ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, product_id bigint(20) NOT NULL COMMENT 农产品ID, warehouse_id bigint(20) DEFAULT 1 COMMENT 仓库ID默认为1, transaction_type tinyint(4) NOT NULL COMMENT 流水类型1-入库2-出库3-盘点调整, quantity decimal(12,3) NOT NULL COMMENT 变动数量入库为正出库为负, unit_price decimal(10,2) DEFAULT NULL COMMENT 本次交易单价, total_amount decimal(14,2) GENERATED ALWAYS AS (quantity * unit_price) STORED COMMENT 总金额生成列, batch_no varchar(64) DEFAULT NULL COMMENT 批次号, production_date date DEFAULT NULL COMMENT 生产日期, expiry_date date DEFAULT NULL COMMENT 过期日期, related_order varchar(128) DEFAULT NULL COMMENT 关联单据号如采购单号、销售单号, operator_id bigint(20) DEFAULT NULL COMMENT 操作员ID, remark varchar(500) DEFAULT NULL COMMENT 备注, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), KEY idx_product_id (product_id), KEY idx_create_time (create_time), KEY idx_batch_no (batch_no), KEY idx_expiry_date (expiry_date) -- 用于保质期预警查询 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT库存流水表;设计要点inventory_transaction.quantity使用有符号数入库为正出库为负。实时库存 该产品所有流水数量的SUM值。这种“流水账”模式比直接更新一个库存数字更可靠易于追溯和核对。expiry_date字段和索引是为“保质期预警”功能准备的。使用了生成列total_amount自动计算金额确保数据一致性。5. 核心业务模块代码实现我们聚焦于最核心的“库存流水”业务实现其新增入库和查询实时库存的功能。5.1 实体类 (Entity) 创建使用Lombok简化代码。// 文件src/main/java/com/agri/inventory/entity/InventoryTransaction.java package com.agri.inventory.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.math.BigDecimal; import java.util.Date; Data TableName(inventory_transaction) // 指定对应表名 public class InventoryTransaction { TableId(type IdType.AUTO) // 主键自增 private Long id; private Long productId; private Long warehouseId; private Integer transactionType; // 1-入库2-出库3-盘点 private BigDecimal quantity; private BigDecimal unitPrice; // 注意total_amount是数据库生成列实体类通常不映射或只读 private String batchNo; private Date productionDate; private Date expiryDate; private String relatedOrder; private Long operatorId; private String remark; TableField(fill FieldFill.INSERT) // 自动填充创建时间 private Date createTime; }5.2 Mapper接口MyBatis-Plus的通用Mapper省去了基础的CRUD SQL。// 文件src/main/java/com/agri/inventory/mapper/InventoryTransactionMapper.java package com.agri.inventory.mapper; import com.agri.inventory.entity.InventoryTransaction; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.math.BigDecimal; Mapper public interface InventoryTransactionMapper extends BaseMapperInventoryTransaction { // 自定义SQL查询某个产品在当前仓库的实时库存所有未删除流水数量的总和 Select(SELECT IFNULL(SUM(quantity), 0) FROM inventory_transaction WHERE product_id #{productId} AND warehouse_id #{warehouseId}) BigDecimal getCurrentStock(Param(productId) Long productId, Param(warehouseId) Long warehouseId); }5.3 Service层业务逻辑实现这里是业务核心包含入库操作和库存查询。// 文件src/main/java/com/agri/inventory/service/InventoryService.java (接口) package com.agri.inventory.service; import com.agri.inventory.dto.StockInDTO; import com.agri.inventory.vo.CurrentStockVO; import java.math.BigDecimal; public interface InventoryService { /** * 农产品入库 * param stockInDTO 入库信息 * return 是否成功 */ boolean stockIn(StockInDTO stockInDTO); /** * 获取农产品实时库存 * param productId 产品ID * param warehouseId 仓库ID * return 库存信息 */ CurrentStockVO getCurrentStock(Long productId, Long warehouseId); }// 文件src/main/java/com/agri/inventory/service/impl/InventoryServiceImpl.java (实现类) package com.agri.inventory.service.impl; import com.agri.inventory.dto.StockInDTO; import com.agri.inventory.entity.InventoryTransaction; import com.agri.inventory.entity.Product; import com.agri.inventory.mapper.InventoryTransactionMapper; import com.agri.inventory.mapper.ProductMapper; import com.agri.inventory.service.InventoryService; import com.agri.inventory.vo.CurrentStockVO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.Date; Slf4j Service RequiredArgsConstructor // Lombok注解自动注入final字段 public class InventoryServiceImpl implements InventoryService { private final InventoryTransactionMapper transactionMapper; private final ProductMapper productMapper; Override Transactional(rollbackFor Exception.class) // 声明式事务异常则回滚 public boolean stockIn(StockInDTO dto) { // 1. 参数校验实际项目应使用Validation注解此处简化 if (dto.getProductId() null || dto.getQuantity() null || dto.getQuantity().compareTo(BigDecimal.ZERO) 0) { throw new IllegalArgumentException(入库参数不合法); } // 2. 验证产品是否存在 Product product productMapper.selectById(dto.getProductId()); if (product null) { throw new RuntimeException(农产品不存在ID: dto.getProductId()); } // 3. 构建流水记录 InventoryTransaction transaction new InventoryTransaction(); transaction.setProductId(dto.getProductId()); transaction.setWarehouseId(dto.getWarehouseId() ! null ? dto.getWarehouseId() : 1L); // 默认仓库 transaction.setTransactionType(1); // 1代表入库 transaction.setQuantity(dto.getQuantity()); transaction.setUnitPrice(dto.getUnitPrice() ! null ? dto.getUnitPrice() : product.getUnitPrice()); transaction.setBatchNo(dto.getBatchNo()); transaction.setProductionDate(dto.getProductionDate()); // 计算过期日期如果提供了生产日期和保质期 if (dto.getProductionDate() ! null product.getShelfLifeDays() ! null) { Date expiryDate cn.hutool.core.date.DateUtil.offsetDay(dto.getProductionDate(), product.getShelfLifeDays()); transaction.setExpiryDate(expiryDate); } else { transaction.setExpiryDate(dto.getExpiryDate()); } transaction.setRelatedOrder(dto.getRelatedOrder()); transaction.setOperatorId(dto.getOperatorId()); transaction.setRemark(dto.getRemark()); // 4. 插入流水记录 int insertResult transactionMapper.insert(transaction); log.info(农产品入库成功流水ID: {}, 产品: {}, 数量: {}, transaction.getId(), product.getProductName(), dto.getQuantity()); // 5. 可选更新产品的最近信息如最近进价 // product.setLatestPrice(transaction.getUnitPrice()); // productMapper.updateById(product); return insertResult 0; } Override public CurrentStockVO getCurrentStock(Long productId, Long warehouseId) { BigDecimal currentStock transactionMapper.getCurrentStock(productId, warehouseId ! null ? warehouseId : 1L); Product product productMapper.selectById(productId); CurrentStockVO vo new CurrentStockVO(); vo.setProductId(productId); vo.setProductName(product ! null ? product.getProductName() : 未知产品); vo.setWarehouseId(warehouseId ! null ? warehouseId : 1L); vo.setCurrentStock(currentStock); vo.setUnit(product ! null ? product.getUnit() : N/A); return vo; } }5.4 DTO与VO对象用于前后端数据交互与Entity解耦。// 文件src/main/java/com/agri/inventory/dto/StockInDTO.java package com.agri.inventory.dto; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.Date; Data public class StockInDTO { NotNull(message 产品ID不能为空) private Long productId; private Long warehouseId; NotNull(message 入库数量不能为空) private BigDecimal quantity; private BigDecimal unitPrice; // 本次入库单价 private String batchNo; private Date productionDate; private Date expiryDate; private String relatedOrder; private Long operatorId; private String remark; }// 文件src/main/java/com/agri/inventory/vo/CurrentStockVO.java package com.agri.inventory.vo; import lombok.Data; import java.math.BigDecimal; Data public class CurrentStockVO { private Long productId; private String productName; private Long warehouseId; private BigDecimal currentStock; private String unit; }5.5 Controller层提供RESTful API处理HTTP请求调用Service返回统一格式的响应。// 文件src/main/java/com/agri/inventory/controller/InventoryController.java package com.agri.inventory.controller; import com.agri.inventory.common.R; import com.agri.inventory.dto.StockInDTO; import com.agri.inventory.service.InventoryService; import com.agri.inventory.vo.CurrentStockVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; Slf4j RestController RequestMapping(/api/inventory) RequiredArgsConstructor public class InventoryController { private final InventoryService inventoryService; /** * 农产品入库接口 * param stockInDTO 入库数据 * return 统一响应结果 */ PostMapping(/stock-in) public RBoolean stockIn(Valid RequestBody StockInDTO stockInDTO) { try { boolean success inventoryService.stockIn(stockInDTO); return success ? R.ok(true, 入库成功) : R.fail(入库失败); } catch (IllegalArgumentException e) { return R.fail(e.getMessage()); } catch (RuntimeException e) { log.error(入库业务异常, e); return R.fail(入库失败 e.getMessage()); } catch (Exception e) { log.error(入库系统异常, e); return R.fail(系统异常入库失败); } } /** * 查询实时库存 * param productId 产品ID * param warehouseId 仓库ID可选 * return 库存信息 */ GetMapping(/current-stock) public RCurrentStockVO getCurrentStock(RequestParam Long productId, RequestParam(required false) Long warehouseId) { CurrentStockVO currentStock inventoryService.getCurrentStock(productId, warehouseId); return R.ok(currentStock); } }5.6 统一响应封装定义统一的API响应格式方便前端处理。// 文件src/main/java/com/agri/inventory/common/R.java package com.agri.inventory.common; import lombok.Data; import java.io.Serializable; Data public class RT implements Serializable { private Integer code; private String msg; private T data; private R(Integer code, String msg, T data) { this.code code; this.msg msg; this.data data; } public static T RT ok(T data) { return new R(200, success, data); } public static T RT ok(T data, String msg) { return new R(200, msg, data); } public static T RT fail(String msg) { return new R(500, msg, null); } // 可以扩展更多状态码如 400参数错误401未授权等 }6. 功能测试与API验证代码写完后必须进行测试。我们使用Postman来模拟前端调用。6.1 启动项目确保MySQL服务已启动数据库agri_inventory_db已创建。在IDEA中运行主启动类InventoryManagementApplication通常位于com.agri.inventory包下。看到类似以下日志表示启动成功Tomcat started on port(s): 8080 (http) Started InventoryManagementApplication in 5.123 seconds6.2 测试入库接口 (POST /api/inventory/stock-in)URL:http://localhost:8080/api/inventory/stock-inMethod: POSTHeaders:Content-Type: application/jsonBody (raw JSON):{ productId: 1, warehouseId: 1, quantity: 100.5, unitPrice: 2.80, batchNo: PC20231027001, productionDate: 2023-10-27, relatedOrder: PO-20231027-001, operatorId: 1, remark: 新鲜土豆采购入库 }预期成功响应:{ code: 200, msg: 入库成功, data: true }验证数据库执行SELECT * FROM inventory_transaction;应该能看到一条transaction_type1的入库记录。6.3 测试查询库存接口 (GET /api/inventory/current-stock)URL:http://localhost:8080/api/inventory/current-stock?productId1warehouseId1Method: GET预期响应:{ code: 200, msg: success, data: { productId: 1, productName: 土豆, // 假设产品表里名字是土豆 warehouseId: 1, currentStock: 100.5, unit: 斤 } }再执行一次出库transaction_type2,quantity为负值后再次查询库存应相应减少。7. 常见问题与排查思路在开发过程中你几乎一定会遇到以下问题。这里提供清晰的排查路径。问题现象可能原因排查方式解决方案启动报错Failed to configure a DataSource1.application.yml中数据库连接信息错误。2. MySQL服务未启动。3. 数据库agri_inventory_db不存在。1. 检查application.yml的url,username,password。2. 命令行执行mysql -u root -p看能否登录。3. 在MySQL中执行SHOW DATABASES;查看数据库是否存在。1. 修正配置。2. 启动MySQL服务。3. 执行提供的SQL脚本创建数据库和表。插入数据时报主键重复或字段太长1. 表结构定义与实体类字段类型/长度不匹配。2. 唯一约束冲突如重复的product_code。1. 对比实体类TableField注解与数据库表DDL。2. 查看MyBatis-Plus打印的SQL日志看插入的具体值。1. 调整实体类或修改表结构使其一致。2. 检查业务逻辑确保唯一性字段的值不重复。调用入库API返回400错误1. 请求体JSON格式错误。2. DTO字段验证失败如NotNull字段为null。1. 检查Postman中JSON格式、引号、括号。2. 查看后端控制台日志Spring会打印详细的参数绑定和验证错误信息。1. 修正JSON。2. 根据日志提示提供必填字段或修正字段格式。事务不生效部分失败数据未回滚1. 异常未被抛出或未被Transactional捕获如被catch吞掉。2. 方法不是public。3. 在同一个类内部方法调用走了代理。1. 检查Service方法是否抛出了Exception或RuntimeException。2. 确保方法是public。3. 将事务方法放在另一个Service类中调用。1. 在catch块中throw new RuntimeException(e);。2. 确保方法为public。3. 使用AopContext.currentProxy()或重构代码结构。查询库存始终为01.productId或warehouseId传错了数据库没有对应流水。2. Mapper中自定义SQL的SUM函数对NULL值处理不当。1. 直接去数据库查SELECT * FROM inventory_transaction WHERE product_id?。2. 检查Mapper的SQL确保IFNULL(SUM(quantity), 0)。1. 确认传入的ID正确并已有入库流水。2. 使用IFNULL或COALESCE函数确保无记录时返回0。MyBatis-Plus打印的SQL中字段名带反引号或错误实体类属性名与数据库字段名映射规则不一致如createTimevscreate_time。查看MyBatis-Plus的配置默认是下划线转驼峰。检查表字段是否都是下划线命名。1. 在application.yml中配置mybatis-plus.configuration.map-underscore-to-camel-case: true默认true。2. 或在字段上使用TableField(create_time)显式指定。8. 项目扩展与生产环境建议一个完整的毕设项目除了核心CRUD还需要考虑更多工程化问题。8.1 功能扩展建议出库与销售模块实现出库接口核心是插入一条transaction_type2且quantity为负的流水。需要增加库存不足的校验。库存盘点与调整实现盘点功能transaction_type3用于修正库存差异。保质期预警编写一个定时任务或查询接口基于inventory_transaction.expiry_date字段查询临近过期的农产品库存。报表统计使用MyBatis动态SQL或JPA Criteria API实现按日、周、月的入库/出库/库存报表。权限控制集成Spring Security或Shiro实现基于角色的菜单和接口访问控制。前端界面使用VueElement UI或ReactAnt Design构建管理后台通过Axios调用后端API。8.2 工程化与最佳实践统一异常处理使用ControllerAdvice和ExceptionHandler全局捕获异常返回统一的错误格式而不是在每个Controller里try-catch。接口文档集成Swagger或Knife4j自动生成API文档方便前后端联调。配置分离将数据库密码等敏感信息放入application-dev.yml、application-prod.yml通过Spring Profile激活不同环境配置。单元测试为Service层关键方法编写JUnit单元测试确保核心业务逻辑正确。日志规范使用SLF4JLogback合理设置日志级别关键业务操作如入库、出库记录操作日志。数据库优化为高频查询条件如product_id,create_time,expiry_date建立索引。定期归档历史流水数据到备份表。部署使用Maven打包成Jar文件通过java -jar命令在服务器运行。考虑使用Docker容器化部署或通过Jenkins实现CI/CD。通过以上步骤你不仅完成了一个可运行的“农产品库存管理系统”核心模块更掌握了从环境搭建、数据库设计、分层开发、API编写到测试部署的完整SpringBoot项目开发流程。这个项目骨架清晰、代码规范你可以在此基础上继续填充其他模块分类管理、供应商管理、报表等最终形成一个丰满的、足以应对毕业答辩的完整系统。建议你将代码托管到GitHub或Gitee并撰写详细的README这本身也是工程能力的重要体现。

相关新闻

最新新闻

日新闻

周新闻

月新闻