基于SpringBoot+MyBatis-Plus的物资管理系统开发实战
1. 项目背景与核心概念在公共卫生事件应急管理中物资的高效、精准管理是保障一线工作顺利开展的关键。传统的人工登记、Excel表格管理方式在面对海量物资的入库、出库、调拨和盘点时不仅效率低下而且极易出现数据错漏、信息不透明、追溯困难等问题。一个专门为应急物资设计的数字化管理系统能够实现物资全生命周期的闭环管理提升响应速度和决策准确性。本项目“新冠物资管理系统”正是基于此背景采用当前主流的Java技术栈进行设计与实现。它是一个典型的Web应用旨在模拟一个真实场景下的物资管理后台涵盖用户管理、物资分类、供应商管理、入库出库、库存盘点、数据统计等核心功能。通过这个项目开发者可以系统地学习如何将一个业务需求转化为具体的软件系统并掌握SpringBoot框架在实际项目开发中的综合应用。核心概念解析SpringBoot本项目的核心框架。它简化了基于Spring的应用初始搭建和开发过程通过自动配置和起步依赖让开发者能快速构建独立、生产级的Spring应用程序。在本项目中它负责整合Web MVC、数据访问、事务管理等组件。MySQL本项目的关系型数据库。用于持久化存储所有业务数据如用户信息、物资信息、出入库记录等。其稳定性和事务支持特性保证了数据的一致性和可靠性。MyBatis-Plus一个强大的MyBatis增强工具。它提供了通用的Mapper和Service只需简单配置即可实现单表基本的CRUD操作极大减少了开发者的SQL编写工作量是本项目数据访问层的核心。Thymeleaf一个用于Web和独立环境的现代服务器端Java模板引擎。在本项目中它负责渲染后端传递的数据到HTML页面实现前后端不分离的经典MVC模式下的视图层展示。Maven项目构建和依赖管理工具。它通过一个中心化的pom.xml文件来管理项目所需的所有第三方库Jar包并定义项目的构建生命周期。学习本项目你将能掌握从环境搭建、数据库设计、后端业务逻辑开发、到前端页面整合的全流程理解一个完整的管理系统是如何运作的并为学习更复杂的微服务或前后端分离架构打下坚实基础。2. 环境准备与版本说明在开始编码之前请确保你的开发环境已就绪。以下版本为本文演示所用你可以根据实际情况进行调整但需注意各组件间的版本兼容性。操作系统Windows 10 / 11 macOS 或 Linux本文命令以Windows为例Java开发工具包JDKJDK 8 或 JDK 11推荐JDK 11LTS长期支持版本检查命令java -version集成开发环境IDEIntelliJ IDEA社区版或旗舰版均可推荐使用项目构建工具Apache Maven 3.6检查命令mvn -v数据库MySQL 5.7 或 MySQL 8.0本文使用MySQL 8.0需要提前安装并启动MySQL服务。浏览器Chrome 或 Edge用于测试系统界面。版本依赖说明关键本项目基于SpringBoot 2.7.x 版本构建。SpringBoot 2.x 与 3.x 在包路径javax迁移到jakarta和部分默认配置上有重大变更直接替换可能导致项目无法启动。请务必使用与示例匹配或兼容的依赖版本。3. 系统设计与数据库建模在动手写代码前清晰的设计是成功的基石。我们需要先分析系统有哪些功能模块功能设计然后确定这些功能需要哪些数据来支撑数据库设计。3.1 系统功能模块设计一个完整的物资管理系统通常包含以下核心模块系统管理用户登录、注销、角色权限管理如管理员、普通操作员。基础数据管理物资分类管理、供应商信息管理、仓库信息管理。物资管理物资信息的增删改查包括物资名称、规格、单位、当前库存等。入库管理记录物资采购或捐赠入库的详细信息生成入库单。出库管理记录物资申领或调配出库的详细信息生成出库单。库存管理实时查看所有物资的库存量进行库存盘点核对实际库存与系统记录。统计报表以图表形式展示物资入库/出库趋势、库存预警、供应商供货统计等。3.2 数据库表结构设计根据功能模块我们设计以下几张核心表1. 用户表 (sys_user)存储系统登录用户信息。CREATE TABLE sys_user ( id int NOT NULL AUTO_INCREMENT COMMENT 主键, username varchar(50) NOT NULL COMMENT 用户名, password varchar(100) NOT NULL COMMENT 密码, real_name varchar(50) DEFAULT NULL COMMENT 真实姓名, user_type char(1) DEFAULT 2 COMMENT 用户类型1管理员2普通用户, status char(1) DEFAULT 1 COMMENT 状态1正常0停用, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uni_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;2. 物资分类表 (goods_type)对物资进行分类如“防护用品”、“消毒用品”、“医疗设备”等。CREATE TABLE goods_type ( id int NOT NULL AUTO_INCREMENT, type_name varchar(100) NOT NULL COMMENT 分类名称, remark varchar(500) DEFAULT NULL COMMENT 备注, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT物资分类表;3. 物资信息表 (goods_info)存储具体的物资信息。CREATE TABLE goods_info ( id int NOT NULL AUTO_INCREMENT, goods_name varchar(200) NOT NULL COMMENT 物资名称, goods_type_id int NOT NULL COMMENT 物资分类ID, specs varchar(100) DEFAULT NULL COMMENT 规格型号, unit varchar(20) DEFAULT NULL COMMENT 单位如个、箱、瓶, stock int DEFAULT 0 COMMENT 当前库存数量, remark varchar(500) DEFAULT NULL COMMENT 备注, PRIMARY KEY (id), KEY idx_type (goods_type_id), CONSTRAINT fk_goods_type FOREIGN KEY (goods_type_id) REFERENCES goods_type (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT物资信息表;4. 入库记录表 (in_stock)记录每一次物资入库的详情。CREATE TABLE in_stock ( id int NOT NULL AUTO_INCREMENT, in_num varchar(50) NOT NULL COMMENT 入库单号可自动生成如IN20231001001, goods_id int NOT NULL COMMENT 物资ID, supplier_id int DEFAULT NULL COMMENT 供应商ID, in_price decimal(10,2) DEFAULT NULL COMMENT 入库单价, in_count int NOT NULL COMMENT 入库数量, total_price decimal(10,2) GENERATED ALWAYS AS ((in_price * in_count)) STORED COMMENT 总金额, in_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 入库时间, operator varchar(50) DEFAULT NULL COMMENT 操作人, remark varchar(500) DEFAULT NULL COMMENT 备注, PRIMARY KEY (id), KEY idx_goods (goods_id), KEY idx_supplier (supplier_id), CONSTRAINT fk_in_goods FOREIGN KEY (goods_id) REFERENCES goods_info (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT入库记录表;注supplier_id关联一个假设的supplier供应商表为简化篇幅其建表语句省略。total_price为生成列自动计算。5. 出库记录表 (out_stock)记录每一次物资出库的详情。CREATE TABLE out_stock ( id int NOT NULL AUTO_INCREMENT, out_num varchar(50) NOT NULL COMMENT 出库单号, goods_id int NOT NULL COMMENT 物资ID, out_count int NOT NULL COMMENT 出库数量, recipient varchar(100) DEFAULT NULL COMMENT 领用人/单位, out_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 出库时间, operator varchar(50) DEFAULT NULL COMMENT 操作人, remark varchar(500) DEFAULT NULL COMMENT 备注, PRIMARY KEY (id), KEY idx_goods (goods_id), CONSTRAINT fk_out_goods FOREIGN KEY (goods_id) REFERENCES goods_info (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT出库记录表;设计要点主键与外键使用id作为自增主键。通过外键如goods_type_id,goods_id维护表间关系保证数据完整性。索引对经常用于查询条件的字段如goods_type_id,goods_id建立索引提升查询性能。数据字典像user_type、status这类字段使用明确的字符如‘1’‘0’代表状态并在代码或注释中定义其含义。业务字段包含必要的业务信息如单号、时间、操作人、备注等便于审计和追溯。4. SpringBoot项目初始化与核心配置4.1 使用Spring Initializr创建项目最快捷的方式是使用IntelliJ IDEA内置的Spring Initializr。打开IDEA选择File - New - Project。左侧选择Spring Initializr选择合适的JDK版本。填写项目元数据Group:com.example(可自定义如com.epidemic)Artifact:material-managementType:MavenJava Version:8或11Packaging:Jar在Dependencies中添加本项目所需的起步依赖Spring Web(用于构建Web MVC)Thymeleaf(模板引擎)MyBatis Framework(或直接添加MyBatis-Plus依赖稍后在pom.xml中手动添加更准确)MySQL Driver(数据库驱动)Lombok(简化实体类代码可选但推荐)点击FinishIDEA会自动生成项目骨架并下载依赖。4.2 配置pom.xml与核心依赖生成的pom.xml需要调整特别是要加入MyBatis-Plus的依赖。以下是关键部分?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 modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId !-- 使用2.7.x稳定版本 -- version2.7.18/version relativePath/ /parent groupIdcom.example/groupId artifactIdmaterial-management/artifactId version0.0.1-SNAPSHOT/version namematerial-management/name description新冠物资管理系统/description properties java.version11/java.version !-- 定义MyBatis-Plus版本 -- mybatis-plus.version3.5.3.1/mybatis-plus.version /properties dependencies !-- SpringBoot Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Thymeleaf -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency !-- MyBatis-Plus 起步依赖 (包含了MyBatis核心和SpringBoot整合) -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version${mybatis-plus.version}/version /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- 测试 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin /plugins /build /project4.3 配置application.yml在src/main/resources目录下创建application.yml文件或修改已有的application.properties配置数据库连接、MyBatis-Plus、Thymeleaf等。server: port: 8080 # 服务端口 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver # 修改为你本地的数据库URL、用户名和密码 url: jdbc:mysql://localhost:3306/material_db?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai username: root password: yourpassword thymeleaf: cache: false # 开发时关闭缓存修改页面立即生效 mode: HTML encoding: UTF-8 # MyBatis-Plus 配置 mybatis-plus: configuration: # 控制台打印执行的SQL开发环境开启便于调试 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true # 自动将下划线命名转为驼峰命名 global-config: db-config: id-type: auto # 主键策略数据库自增 logic-delete-field: isDeleted # 全局逻辑删除字段名若需要 logic-delete-value: 1 # 逻辑已删除值 logic-not-delete-value: 0 # 逻辑未删除值 # 指定mapper.xml文件的位置如果使用注解则可不配 mapper-locations: classpath*:/mapper/**/*.xml # 日志级别 logging: level: com.example.materialmanagement.mapper: debug # 将mapper接口的日志级别设为debug可看到SQL配置解释spring.datasource: 配置连接MySQL数据库的基本信息。mybatis-plus.configuration.log-impl: 开启SQL日志是开发阶段排查问题的利器。map-underscore-to-camel-case: 非常重要它实现了数据库字段名user_name与Java实体类属性名userName的自动映射。5. 核心功能模块开发实战项目采用经典的三层架构Controller控制层、Service业务层、Mapper数据访问层。下面我们以实现“物资信息管理”模块为例贯穿整个开发流程。5.1 创建实体类Entity对应数据库表goods_info。使用Lombok注解简化代码。// 文件路径src/main/java/com/example/materialmanagement/entity/GoodsInfo.java package com.example.materialmanagement.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.util.Date; Data TableName(goods_info) // 指定对应的数据库表名 public class GoodsInfo { TableId(value id, type IdType.AUTO) // 主键自增 private Integer id; TableField(goods_name) // 可省略因为开启了驼峰映射 private String goodsName; TableField(goods_type_id) private Integer goodsTypeId; private String specs; private String unit; private Integer stock; private String remark; // 非数据库字段用于在页面上显示分类名称 TableField(exist false) private String goodsTypeName; TableField(exist false) private Date createTime; }Data: Lombok注解自动生成getter、setter、toString等方法。TableName,TableId,TableField: MyBatis-Plus注解用于对象-关系映射。TableField(exist false): 标明该字段不是数据库表字段。5.2 创建Mapper接口MyBatis-Plus的强大之处在于对于单表操作我们甚至不需要写XML文件。// 文件路径src/main/java/com/example/materialmanagement/mapper/GoodsInfoMapper.java package com.example.materialmanagement.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.materialmanagement.entity.GoodsInfo; import org.apache.ibatis.annotations.Mapper; Mapper // 标记为MyBatis的MapperSpringBoot会自动扫描 public interface GoodsInfoMapper extends BaseMapperGoodsInfo { // 继承BaseMapper后即拥有了基本的CRUD方法insert, deleteById, updateById, selectById, selectList等 // 复杂查询可以在此处定义方法并配合Select注解或XML文件 }5.3 创建Service接口及其实现业务逻辑层负责处理复杂的业务规则。接口// 文件路径src/main/java/com/example/materialmanagement/service/GoodsInfoService.java package com.example.materialmanagement.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.materialmanagement.entity.GoodsInfo; import java.util.List; public interface GoodsInfoService extends IServiceGoodsInfo { // 可以在此定义特殊的业务方法 ListGoodsInfo getGoodsListWithType(); // 查询物资列表并关联分类名称 }实现类// 文件路径src/main/java/com/example/materialmanagement/service/impl/GoodsInfoServiceImpl.java package com.example.materialmanagement.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.materialmanagement.entity.GoodsInfo; import com.example.materialmanagement.mapper.GoodsInfoMapper; import com.example.materialmanagement.service.GoodsInfoService; import org.springframework.stereotype.Service; import java.util.List; Service // 标记为Spring的Service组件 public class GoodsInfoServiceImpl extends ServiceImplGoodsInfoMapper, GoodsInfo implements GoodsInfoService { Override public ListGoodsInfo getGoodsListWithType() { // 1. 查询所有物资 ListGoodsInfo goodsList this.list(); // 2. 为每个物资设置分类名称这里简化处理实际应通过关联查询一次完成 // 假设有一个GoodsTypeService // for (GoodsInfo goods : goodsList) { // GoodsType type goodsTypeService.getById(goods.getGoodsTypeId()); // goods.setGoodsTypeName(type ! null ? type.getTypeName() : ); // } // 此处仅为示例更优做法是在Mapper中编写联表查询SQL。 return goodsList; } }ServiceImplGoodsInfoMapper, GoodsInfo: MyBatis-Plus提供的通用Service实现已经注入了baseMapper可以直接使用。复杂的业务逻辑如关联查询应在Service层实现。简单的单表操作可以直接在Controller中调用baseMapper的方法。5.4 创建Controller控制层接收前端请求调用Service返回数据或视图。// 文件路径src/main/java/com/example/materialmanagement/controller/GoodsInfoController.java package com.example.materialmanagement.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.materialmanagement.entity.GoodsInfo; import com.example.materialmanagement.service.GoodsInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; Controller RequestMapping(/goods) public class GoodsInfoController { Autowired private GoodsInfoService goodsInfoService; /** * 分页查询物资列表 * param pageNum 页码 * param pageSize 每页条数 * param model * return */ GetMapping(/list) public String list(RequestParam(value pageNum, defaultValue 1) Integer pageNum, RequestParam(value pageSize, defaultValue 10) Integer pageSize, Model model) { // 构建分页对象 PageGoodsInfo page new Page(pageNum, pageSize); // 构建查询条件示例按ID倒序 QueryWrapperGoodsInfo queryWrapper new QueryWrapper(); queryWrapper.orderByDesc(id); // 执行分页查询 PageGoodsInfo goodsPage goodsInfoService.page(page, queryWrapper); // 将数据放入Model供Thymeleaf渲染 model.addAttribute(pageData, goodsPage); return goods/list; // 返回视图名称对应 templates/goods/list.html } /** * 跳转到新增页面 */ GetMapping(/toAdd) public String toAdd() { return goods/add; } /** * 执行新增操作 */ PostMapping(/add) public String add(GoodsInfo goodsInfo) { // 简单校验实际项目应使用Validation注解或更复杂的校验逻辑 if (goodsInfo.getGoodsName() null || goodsInfo.getGoodsName().trim().isEmpty()) { // 可以返回错误信息这里简化处理 return redirect:/goods/toAdd?error名称不能为空; } goodsInfo.setStock(0); // 新增物资初始库存为0 goodsInfoService.save(goodsInfo); return redirect:/goods/list; // 重定向到列表页 } /** * 跳转到编辑页面 */ GetMapping(/toEdit/{id}) public String toEdit(PathVariable(id) Integer id, Model model) { GoodsInfo goods goodsInfoService.getById(id); if (goods null) { return redirect:/goods/list; } model.addAttribute(goods, goods); return goods/edit; } /** * 执行更新操作 */ PostMapping(/update) public String update(GoodsInfo goodsInfo) { goodsInfoService.updateById(goodsInfo); return redirect:/goods/list; } /** * 删除物资 */ GetMapping(/delete/{id}) public String delete(PathVariable(id) Integer id) { // 实际业务中需要判断该物资是否有库存或关联出入库记录有则不能删除 goodsInfoService.removeById(id); return redirect:/goods/list; } }Controller: 声明为控制器返回视图名称。RequestMapping(“/goods”): 类级别的请求映射该控制器下所有方法的URL都以/goods开头。GetMapping,PostMapping: 定义具体的HTTP请求方法映射。Model: Spring MVC提供的模型用于在控制器和视图间传递数据。return “goods/list”;: 返回逻辑视图名Thymeleaf会根据spring.thymeleaf.prefix默认classpath:/templates/和.suffix默认.html找到实际文件/templates/goods/list.html。5.5 创建Thymeleaf页面在src/main/resources/templates下创建目录和HTML文件。列表页 (/templates/goods/list.html) 核心片段!DOCTYPE html html langzh xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title物资列表/title !-- 引入Bootstrap CSS -- link hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.1.3/dist/css/bootstrap.min.css relstylesheet /head body div classcontainer mt-4 h2物资信息管理/h2 a th:href{/goods/toAdd} classbtn btn-primary mb-3新增物资/a table classtable table-bordered table-hover thead tr thID/th th物资名称/th th分类/th th规格/th th单位/th th库存/th th操作/th /tr /thead tbody !-- 使用Thymeleaf遍历分页数据 -- tr th:eachgoods : ${pageData.records} td th:text${goods.id}/td td th:text${goods.goodsName}/td td th:text${goods.goodsTypeId}/td !-- 实际应显示分类名 -- td th:text${goods.specs}/td td th:text${goods.unit}/td td th:text${goods.stock}/td td a th:href{/goods/toEdit/{id}(id${goods.id})} classbtn btn-sm btn-warning编辑/a a th:href{/goods/delete/{id}(id${goods.id})} classbtn btn-sm btn-danger onclickreturn confirm(确定删除吗)删除/a /td /tr /tbody /table !-- 分页组件 -- nav ul classpagination li classpage-item th:classappend${pageData.current 1} ? disabled : a classpage-link th:href{/goods/list(pageNum${pageData.current-1})}上一页/a /li li classpage-item th:eachpageNum : ${#numbers.sequence(1, pageData.pages)} th:classappend${pageData.current pageNum} ? active : a classpage-link th:href{/goods/list(pageNum${pageNum})} th:text${pageNum}/a /li li classpage-item th:classappend${pageData.current pageData.pages} ? disabled : a classpage-link th:href{/goods/list(pageNum${pageData.current1})}下一页/a /li /ul /nav /div /body /htmlxmlns:th”http://www.thymeleaf.org”: 引入Thymeleaf命名空间。th:href,th:text,th:each: Thymeleaf属性用于动态生成URL、文本和循环。th:object,th:field: 在表单页面用于数据绑定在add/edit页面中使用。6. 运行与验证启动MySQL服务并创建数据库material_db执行第3.2节中的SQL建表语句。启动SpringBoot应用。在IDEA中找到主启动类通常命名为MaterialManagementApplication右键Run。观察控制台日志看到Tomcat started on port(s): 8080且没有报错说明启动成功。访问系统。打开浏览器输入http://localhost:8080。由于我们还没有配置默认首页会看到Whitelabel Error Page。直接访问我们定义的接口http://localhost:8080/goods/list。如果一切正常你应该能看到一个简单的物资列表页面此时数据为空。点击“新增物资”填写表单提交后数据应能保存到数据库并在列表页显示。7. 常见问题与排查思路在开发过程中你可能会遇到以下典型问题问题现象可能原因排查步骤与解决方案应用启动失败报DataSource相关错误1. 数据库连接URL、用户名、密码错误。2. MySQL服务未启动。3. 数据库驱动版本不匹配。1. 检查application.yml中的spring.datasource配置。2. 使用命令行或工具连接MySQL确认服务正常。3. 检查pom.xml中MySQL驱动版本是否与安装的MySQL版本兼容MySQL 8.0推荐使用mysql-connector-java8.x。访问页面报404错误1. Controller的RequestMapping路径写错。2. 方法请求方式GET/POST不匹配。3. Thymeleaf模板文件位置或名称不对。1. 检查浏览器地址栏URL与Controller中定义的路径是否一致。2. 使用Postman或浏览器开发者工具查看网络请求确认是GET还是POST。3. 确认HTML文件是否放在/templates下正确子目录且返回的视图名与之匹配注意大小写。页面能访问但显示Whitelabel Error Page或乱码1. Thymeleaf模板语法错误。2. 静态资源CSS/JS加载失败。3. 后端Controller向Model添加的属性名与前端引用名不一致。1. 查看控制台是否有Thymeleaf解析错误日志。2. 检查浏览器开发者工具Console和Network标签看是否有资源404或JS错误。3. 核对model.addAttribute(“key”, value)中的key和HTML中${key}是否一致。控制台不打印SQL日志application.yml中MyBatis-Plus的SQL日志配置未生效或级别不对。1. 确认配置mybatis-plus.configuration.log-impl: org.apache.ibatis.logging.stdout.StdOutImpl。2. 检查logging.level下对应mapper包路径的级别是否为debug。插入或更新数据时字段值为null1. 实体类属性名与数据库字段名映射失败。2. 前端表单name属性与实体类属性名不一致。3. 数据库字段有非空约束但前端未传递值。1. 确认开启了map-underscore-to-camel-case或正确使用了TableField注解。2. 检查HTML表单中input的name属性。3. 检查数据库表结构确认非空字段是否都有值。分页查询失效查出了所有数据未配置MyBatis-Plus的分页插件。在SpringBoot主类或配置类中添加分页插件BeanBeanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor());return interceptor;}8. 项目扩展与最佳实践建议完成基础CRUD后一个完整的系统还需要考虑更多工程化问题。8.1 功能扩展方向用户登录与权限控制集成Spring Security或Shiro实现基于角色的页面和接口权限控制。入库出库业务实现完整的入库单、出库单管理。关键点入库/出库操作需要同步更新goods_info表的stock库存字段这是一个事务操作要保证数据一致性。Transactional(rollbackFor Exception.class) // 声明事务 public boolean addInStock(InStock inStock) { // 1. 添加入库记录 boolean saveSuccess inStockService.save(inStock); // 2. 更新物资库存 GoodsInfo goods goodsInfoService.getById(inStock.getGoodsId()); goods.setStock(goods.getStock() inStock.getInCount()); boolean updateSuccess goodsInfoService.updateById(goods); // 如果任何一步失败事务回滚 return saveSuccess updateSuccess; }库存预警在goods_info表中增加min_stock最低库存字段在列表页或首页对库存低于阈值的物资进行高亮提示。数据统计与图表使用ECharts等前端图表库在后台统计页面展示物资出入库趋势、库存占比等。数据导出使用Apache POI或EasyExcel库实现将物资列表、出入库记录导出为Excel文件。8.2 工程化最佳实践统一响应封装设计一个通用的Result类来包装所有Controller的返回结果包含code、msg、data字段便于前端统一处理。Data public class ResultT { private Integer code; private String msg; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMsg(成功); result.setData(data); return result; } public static T ResultT error(String msg) { ResultT result new Result(); result.setCode(500); result.setMsg(msg); return result; } }全局异常处理使用ControllerAdvice和ExceptionHandler注解创建全局异常处理器捕获系统异常并返回友好的Result对象而不是暴露堆栈信息给用户。参数校验在接收参数的实体类字段上使用javax.validation注解如NotBlank,Min,Max并在Controller方法参数前加Valid注解进行自动校验。日志记录使用SLF4J Logback在Service层关键业务节点如入库、出库记录操作日志便于问题追踪和审计。配置分离将application.yml拆分为application-dev.yml开发环境、application-prod.yml生产环境通过spring.profiles.active指定激活的环境。API文档集成Swagger或Knife4j自动生成和可视化后端API接口文档方便前后端联调。前端优化对于复杂的表单和交互可以考虑引入jQuery或Vue.js来增强用户体验但注意与Thymeleaf的整合方式。通过以上步骤你不仅完成了一个“新冠物资管理系统”的核心功能更实践了使用SpringBootMyBatis-Plus进行企业级应用开发的标准流程。从数据库设计、三层架构搭建、到事务控制、异常处理这些经验是构建任何复杂业务系统的基石。建议你在掌握本项目后尝试自行实现“入库管理”、“出库管理”和“统计报表”模块以巩固所学知识。

相关新闻

GPIO模拟SPI驱动OLED的原理与优化实践

GPIO模拟SPI驱动OLED的原理与优化实践

1. GPIO模拟SPI驱动OLED的核心原理SPI协议本质上是一种同步串行通信方式,通过四根信号线实现全双工通信。当硬件SPI控制器不可用时,GPIO模拟成为最灵活的解决方案。我曾在多个嵌入式项目中采用这种方案,特别是在STM32F103C8T6这类资源受限的M…

2026/7/29 3:06:39 阅读更多 →
ROS2开发为何仍选Eclipse?大型工作空间调试与符号索引实战指南

ROS2开发为何仍选Eclipse?大型工作空间调试与符号索引实战指南

1. 为什么在ROS2开发中还要用Eclipse?这不是“复古”而是务实选择 很多人看到标题第一反应是:“ROS2不是都用VS Code和colcon了吗?怎么还在折腾Eclipse?”——这恰恰是我写这篇实操笔记的出发点。过去三年,我在工业机器…

2026/7/28 18:53:35 阅读更多 →
胡适与江冬秀:新旧文化碰撞下的传统婚礼

胡适与江冬秀:新旧文化碰撞下的传统婚礼

1. 胡适大婚的历史背景与时代意义 1917年12月30日,安徽绩溪上庄村的一场婚礼引起了当地轰动。时年26岁的留美归国学者胡适,在故乡迎娶了比他年长一岁的江冬秀。这场看似普通的传统婚礼,却因其主角的特殊身份而具有了独特的历史意义。 胡适当…

2026/7/27 12:51:55 阅读更多 →

最新新闻

行空板M10嵌入式语音合成实战:集成讯飞离线与百度云端双引擎

行空板M10嵌入式语音合成实战:集成讯飞离线与百度云端双引擎

1. 项目缘起:为什么要在行空板上折腾语音引擎?最近在做一个智能交互小装置,核心需求是让设备能“听懂人话”并“开口说话”。手头正好有一块行空板M10,它集成了高性能的处理器和丰富的接口,跑个Linux系统,做…

2026/7/29 6:49:53 阅读更多 →
Android崩溃分析实战:用Python脚本打通Logcat与Firebase Crashlytics

Android崩溃分析实战:用Python脚本打通Logcat与Firebase Crashlytics

1. 项目概述:为什么我们需要一个专门的Logcat插件来分析Firebase崩溃? 如果你是一名Android开发者,尤其是在处理线上应用崩溃问题时,Firebase Crashlytics(现在已整合到Firebase Crash Reporting中)几乎是…

2026/7/29 6:49:53 阅读更多 →
多传感器融合算法:从UKF到AUKF的工程实践

多传感器融合算法:从UKF到AUKF的工程实践

1. 多传感器融合与状态估计的核心挑战在自动驾驶、机器人导航和工业控制等领域,多传感器数据融合一直是提升系统鲁棒性的关键技术。我十年前第一次接触无人机飞控项目时,就深刻体会到单一传感器的局限性——GPS信号丢失时姿态估计完全失效,这…

2026/7/29 6:49:53 阅读更多 →
Flut Renamer:免费高效的跨平台批量文件重命名终极指南

Flut Renamer:免费高效的跨平台批量文件重命名终极指南

Flut Renamer:免费高效的跨平台批量文件重命名终极指南 【免费下载链接】renamer Flut Renamer - A bulk file renamer written in flutter (dart). Available on Linux, Windows, Android, iOS and macOS. 项目地址: https://gitcode.com/gh_mirrors/ren/renamer…

2026/7/29 6:49:53 阅读更多 →
王者荣耀战绩查询API实战:搜索玩家、查看角色与历史战报

王者荣耀战绩查询API实战:搜索玩家、查看角色与历史战报

适用场景 当开发者需要将王者荣耀战绩数据集成到自己的应用中时,例如: 战队数据看板:自动拉取队员近期的排位赛、巅峰赛表现,生成 KDA 统计报表直播辅助工具:主播输入玩家昵称,实时展示当前段位和历史战报个…

2026/7/29 6:49:53 阅读更多 →
从SSRF到Pickle反序列化:Web渗透中的链式漏洞利用实战

从SSRF到Pickle反序列化:Web渗透中的链式漏洞利用实战

1. 项目概述:一次从SSRF到Pickle反序列化的完整攻防推演最近复盘了去年长城杯的一道Web赛题,感觉它把SSRF(服务端请求伪造)和Python Pickle反序列化这两个经典漏洞串联得相当巧妙,实战价值很高。这道题不是那种简单的“…

2026/7/29 6:48:52 阅读更多 →

日新闻

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:00:23 阅读更多 →
AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础 在上一期「AI编程系列」中,我们学习了如何构建一个基础的 AI 问答系统,通过简单的输入输出让模型回应问题。但现实世界中的 AI 应用往往需要处理更复杂的场景:…

2026/7/29 0:00:23 阅读更多 →
AI智能体开发实战:从工具调用到企业级部署

AI智能体开发实战:从工具调用到企业级部署

1. 从被动问答到主动执行:AI Agent的范式转变过去两年,大语言模型最显著的应用形态是聊天机器人——用户提问,AI回答。但真正的生产力革命发生在2023年下半年:当AI学会主动调用工具完成任务时,生产力工具的历史被彻底改…

2026/7/29 0:00:23 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/28 12:04:22 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/28 8:29:16 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/28 5:03:42 阅读更多 →

月新闻