news 2026/8/27 10:19:18

SpringBoot+JDK17实战:从零构建采购管理系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot+JDK17实战:从零构建采购管理系统

1. 背景与项目价值

1.1 为什么要做采购管理系统

在校招、社招简历里,“管理系统”类项目永远是出镜率最高的选题之一。但在实际面试中,面试官最常问的一句话是:“这个系统是你自己从头写的吗?核心模块有哪些?有没有遇到什么坑?”

很多同学用网上下载的 SSM 或 JSP 老项目,代码年代久远,Spring 版本还停留在 XML 配置时代,既跑不起来,也讲不清楚。真正能拿得出手的,是那种技术栈新、结构清晰、功能闭环、能演示能部署的项目。

采购管理系统恰好满足这些要求。它属于典型的企业级 CRUD + 业务流项目,业务逻辑清晰,涉及供应商管理、采购订单、入库管理、库存统计等模块,既有单表操作,也有多表关联和状态流转。用 SpringBoot + JDK17 + MyBatis + MySQL 实现,既能体现 JavaWeb 基本功,又能展示 SpringBoot 的快速开发能力。

1.2 项目适合哪些人群

这个项目适合下面几类读者:

  • Java 初学者:想找一个完整的 JavaWeb 项目练手,而不是零散的 Demo。
  • 毕业设计选题:需要一套能运行、能答辩、有业务深度的系统。
  • 简历项目储备:想在后端岗位面试中有项目可讲,应付“项目细节”追问。
  • 转行学习者:学了 SpringBoot 基础语法后,急需一个完整项目串联零散知识点。

如果你正处于以上任何一种情况,这篇文章值得你从头跟到尾。

1.3 学完能掌握什么

通过本项目,你将掌握:

  • JDK17 的安装与多版本配置,尤其是 Windows 和 Mac 的差异点。
  • SpringBoot 3.x 项目从零搭建的完整流程。
  • MyBatis 或 MyBatis-Plus 操作数据库的常用姿势。
  • 采购业务的数据库表设计思路,包括一对多、多对多关系拆解。
  • Controller、Service、Mapper 三层的代码组织方式。
  • 前端页面(Thymeleaf 或 Vue 静态页)与后端接口的对接方式。
  • 常见启动报错、依赖冲突、端口占用等问题的排查思路。

下面开始实操。整个项目我会按“环境准备 → 数据库设计 → 项目搭建 → 代码实现 → 运行验证”的顺序展开,最后补充常见问题与简历讲解建议。

2. 技术选型与版本说明

2.1 为什么选 SpringBoot + JDK17

很多学校课程还在教 JDK8,但 2024 年以后,JDK17 已经成为 Java 生态的主流长期支持版本。Spring Boot 3.x 官方要求 JDK17 作为最低版本,Tomcat 10、Jakarta EE 9 等标准也全面切换。

SpringBoot 相比传统 SSM 的优势非常明显:

  • 自动配置:不需要手写大量的 XML Bean 配置,默认配置开箱即用。
  • 内嵌服务器:打成 Jar 包后直接java -jar运行,不需要外置 Tomcat。
  • 生态丰富:连接 MySQL、Redis、MQ 等中间件都有对应的 Starter。
  • 运维简单:自带 Actuator 监控,适合微服务部署。

JDK17 本身带来了不少新特性,比如 Switch 表达式、文本块、密封类、增强的伪随机数生成器等。对管理类系统来说,我们最直接感受到的是更稳定、性能更好、长期维护无忧。

2.2 项目技术栈清单

本项目采用的技术栈如下,版本按实际环境调整:

组件推荐版本说明
JDK17+必须 JDK17 及以上,Spring Boot 3.x 强制要求
构建工具Maven 3.8+也可用 Gradle,本文以 Maven 为例
开发工具IntelliJ IDEA社区版/专业版均可,推荐 2023 以上
Spring Boot3.2.x稳定版本,支持 JDK17
MyBatis-Plus3.5.x极大的减少 SQL 编写量
MySQL8.05.7 也能跑,推荐 8.0
前端模板ThymeleafSpringBoot 默认模板引擎,前后端未分离
数据库连接池HikariCPSpringBoot 默认集成

版本需要根据你的项目实际情况调整,本文示例以 Spring Boot 3.2 + JDK17 + MySQL 8 为基准,重点是演示配置思路和代码结构,版本不同时只需要调整依赖坐标。

2.3 JDK17 安装与多版本配置

这里单独说一下 JDK17 的安装,因为不少同学在环境上卡了很久。

Windows 下安装 JDK17

去 Oracle 官网或 Adoptium 下载 JDK17 的 Windows x64 安装包,双击安装。安装时记住安装路径,例如C:\Program Files\Java\jdk-17

安装完成后,配置环境变量:

JAVA_HOME=C:\Program Files\Java\jdk-17 Path=%JAVA_HOME%\bin

配置完成后,在命令行输入:

java -version javac -version

如果输出类似下面内容,说明环境配置成功:

java version "17.0.10" 2024-01-16 LTS Java(TM) SE Runtime Environment (build 17.0.10+11-LTS-120) Java HotSpot(TM) 64-Bit Server VM (build 17.0.10+11-LTS-120, mixed mode, sharing)

Mac 下安装 JDK17

推荐使用 Homebrew:

brew install openjdk@17

安装完成后需要做符号链接,否则java -version可能读不到:

sudo ln -sfn $(brew --prefix)/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk

多版本切换

如果你电脑上同时有 JDK8 和 JDK17,建议使用 JEnv(Mac/Linux)或手动切换 JAVA_HOME(Windows)。不要盲目卸载旧版本,有些老旧项目仍然需要 JDK8 才能编译。

3. 系统功能与数据库设计

3.1 功能模块梳理

采购管理系统这个名字比较宽泛,不同场景有不同的功能范围。为了做一个“能答辩”的项目,我建议覆盖以下核心模块:

  1. 供应商管理:维护供应商基本信息,包括联系人、电话、地址、合作状态。
  2. 采购订单管理:创建采购订单,填写订单编号、供应商、采购日期、订单状态。
  3. 订单明细管理:每个订单关联多个采购商品,记录商品名称、数量、单价、小计。
  4. 商品管理:维护商品档案,包括商品编码、名称、规格、单位。
  5. 入库管理:采购订单到货后执行入库操作,增加库存数量。
  6. 库存管理:查看当前库存数量,支持库存预警提示。
  7. 用户登录与权限:简单的登录功能,区分管理员和普通操作员。

业务逻辑上,核心的流程是:

创建供应商 → 创建商品档案 → 创建采购订单 → 添加订单明细 → 审核订单 → 收货入库 → 更新库存

这样的一组功能闭环,比单纯堆 CRUD 更有说服力。面试时,你可以围绕“订单状态如何流转”“入库时如何防止超卖”这类问题展开。

3.2 数据库表设计

数据库设计是面试高频考点,这个项目至少要保证三张核心表之间的外键关系清晰:供应商表、采购订单表、采购订单明细表。再加上商品表和用户表,组成一套完整业务模型。

下面给出核心表结构的 SQL,这里使用 MySQL 为例。

供应商表supplier

CREATE TABLE supplier ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', supplier_code VARCHAR(32) NOT NULL COMMENT '供应商编码', supplier_name VARCHAR(100) NOT NULL COMMENT '供应商名称', contact_person VARCHAR(50) DEFAULT NULL COMMENT '联系人', contact_phone VARCHAR(20) DEFAULT NULL COMMENT '联系电话', address VARCHAR(255) DEFAULT NULL COMMENT '地址', status TINYINT DEFAULT 1 COMMENT '状态:1启用 0停用', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' ) COMMENT '供应商表';

商品表product

CREATE TABLE product ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', product_code VARCHAR(32) NOT NULL COMMENT '商品编码', product_name VARCHAR(100) NOT NULL COMMENT '商品名称', spec VARCHAR(50) DEFAULT NULL COMMENT '规格型号', unit VARCHAR(20) DEFAULT NULL COMMENT '单位', stock_quantity INT DEFAULT 0 COMMENT '库存数量', warning_quantity INT DEFAULT 10 COMMENT '库存预警值', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' ) COMMENT '商品表';

采购订单表purchase_order

CREATE TABLE purchase_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', order_no VARCHAR(32) NOT NULL COMMENT '订单编号', supplier_id BIGINT NOT NULL COMMENT '供应商ID', supplier_name VARCHAR(100) DEFAULT NULL COMMENT '供应商名称', order_date DATE DEFAULT NULL COMMENT '采购日期', total_amount DECIMAL(12,2) DEFAULT 0.00 COMMENT '总金额', status TINYINT DEFAULT 0 COMMENT '状态:0待审核 1已审核 2已入库 3已取消', remark VARCHAR(255) DEFAULT NULL COMMENT '备注', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' ) COMMENT '采购订单表';

采购订单明细表purchase_order_item

CREATE TABLE purchase_order_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', order_id BIGINT NOT NULL COMMENT '订单ID', product_id BIGINT NOT NULL COMMENT '商品ID', product_name VARCHAR(100) DEFAULT NULL COMMENT '商品名称', price DECIMAL(10,2) DEFAULT 0.00 COMMENT '采购单价', quantity INT DEFAULT 0 COMMENT '采购数量', amount DECIMAL(12,2) DEFAULT 0.00 COMMENT '小计金额' ) COMMENT '采购订单明细表';

用户表sys_user

CREATE TABLE sys_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', username VARCHAR(50) NOT NULL COMMENT '用户名', password VARCHAR(100) NOT NULL COMMENT '密码', real_name VARCHAR(50) DEFAULT NULL COMMENT '真实姓名', role VARCHAR(20) DEFAULT 'USER' COMMENT '角色:ADMIN/USER', status TINYINT DEFAULT 1 COMMENT '状态:1启用 0禁用' ) COMMENT '系统用户表';

这几张表的字段不算多,但足够覆盖日常采购业务。如果你需要做演示数据,可以手动插入几条供应商、商品和订单记录,方便测试列表查询和状态流转。

3.3 数据层设计要点

  • 订单明细中冗余了product_namesupplier_name,虽然有些冗余,但能避免联表查询过多,这种设计在报表场景中很常见。
  • 订单总金额total_amount可以在创建订单时计算并更新,也可以在查询时通过 SUM 计算。生产环境建议保存快照,避免历史订单金额被商品价格变动影响。
  • status字段用数字表示状态,比字符串更省存储,也方便做状态机流转。

4. 项目搭建与核心代码实现

4.1 创建 SpringBoot 项目

推荐直接在 IDEA 中创建:

  1. 打开 IDEA,选择 New Project → Spring Initializr。
  2. 填写项目信息:Group 为com.example,Artifact 为purchase
  3. 指定 Java 版本为 17。
  4. 选择依赖:Spring Web、Thymeleaf、MyBatis Framework、MySQL Driver、Lombok。

如果你是使用 Maven 手工创建,可以在pom.xml中加入以下核心依赖:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.5</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.5</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>

这里特别说明一下 MyBatis-Plus 的坐标:Spring Boot 3 需要引入mybatis-plus-spring-boot3-starter,而不是旧版的mybatis-plus-boot-starter,否则启动时会因为包版本问题抛异常。

4.2 编写核心配置文件

文件路径:src/main/resources/application.yml

server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/purchase_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 thymeleaf: cache: false prefix: classpath:/templates/ suffix: .html mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: id-type: auto

配置说明:

  • map-underscore-to-camel-case: true用于把数据库的下划线字段自动映射为 Java 驼峰属性,例如supplier_code映射到supplierCode
  • log-impl设置为 StdOutImpl,SQL 会打印在控制台,方便调试。
  • 密码和具体数据库名需要换成你自己的。

4.3 编写实体类

以订单和订单明细为例,使用 Lombok 简化 getter/setter。

文件路径:src/main/java/com/example/purchase/entity/PurchaseOrder.java

package com.example.purchase.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; @Data @TableName("purchase_order") public class PurchaseOrder { @TableId(type = IdType.AUTO) private Long id; private String orderNo; private Long supplierId; private String supplierName; private LocalDate orderDate; private BigDecimal totalAmount; private Integer status; private String remark; private LocalDateTime createTime; private LocalDateTime updateTime; }

文件路径:src/main/java/com/example/purchase/entity/PurchaseOrderItem.java

package com.example.purchase.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; @Data @TableName("purchase_order_item") public class PurchaseOrderItem { @TableId(type = IdType.AUTO) private Long id; private Long orderId; private Long productId; private String productName; private BigDecimal price; private Integer quantity; private BigDecimal amount; }

4.4 编写 Mapper 层

Mapper 接口继承 BaseMapper 后,就已经内置了 selectById、insert、updateById、deleteById、selectList 等常用方法,不需要手写 SQL。

文件路径:src/main/java/com/example/purchase/mapper/PurchaseOrderMapper.java

package com.example.purchase.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.purchase.entity.PurchaseOrder; import org.apache.ibatis.annotations.Mapper; @Mapper public interface PurchaseOrderMapper extends BaseMapper<PurchaseOrder> { }

同样的方式创建PurchaseOrderItemMapperSupplierMapperProductMapperSysUserMapper

如果需要自定义查询,例如统计每个供应商的采购总额,可以在 Mapper 中写一个方法,并使用@Select注解:

@Select("SELECT supplier_name, SUM(total_amount) AS total FROM purchase_order WHERE status = 2 GROUP BY supplier_name") List<Map<String, Object>> selectSupplierTotal();

4.5 编写 Service 层

Service 层是核心业务逻辑所在。以订单创建为例,这里需要做的事:

  1. 生成订单编号。
  2. 保存订单主表。
  3. 遍历明细列表,保存每个明细。
  4. 计算订单总金额并更新。

文件路径:src/main/java/com/example/purchase/service/impl/PurchaseOrderServiceImpl.java

package com.example.purchase.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.purchase.entity.PurchaseOrder; import com.example.purchase.entity.PurchaseOrderItem; import com.example.purchase.mapper.PurchaseOrderItemMapper; import com.example.purchase.mapper.PurchaseOrderMapper; import com.example.purchase.service.PurchaseOrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; @Service public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, PurchaseOrder> implements PurchaseOrderService { @Autowired private PurchaseOrderItemMapper purchaseOrderItemMapper; @Override @Transactional(rollbackFor = Exception.class) public void createOrder(PurchaseOrder order, List<PurchaseOrderItem> items) { // 1. 生成订单编号:PO + 年月日时分秒 String orderNo = "PO" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); order.setOrderNo(orderNo); order.setStatus(0); // 2. 计算总金额 BigDecimal total = BigDecimal.ZERO; for (PurchaseOrderItem item : items) { BigDecimal amount = item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())); item.setAmount(amount); total = total.add(amount); } order.setTotalAmount(total); // 3. 保存主表 this.save(order); // 4. 保存明细 for (PurchaseOrderItem item : items) { item.setOrderId(order.getId()); purchaseOrderItemMapper.insert(item); } } }

这里加@Transactional非常必要。如果明细插入过程中出现异常,订单主表也要回滚,否则会出现“主表存在、明细缺失”的脏数据。

4.6 编写 Controller 层

Controller 负责接收请求、调用 Service、返回页面或 JSON 数据。

文件路径:src/main/java/com/example/purchase/controller/OrderController.java

package com.example.purchase.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.example.purchase.entity.PurchaseOrder; import com.example.purchase.service.PurchaseOrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import java.util.List; @Controller @RequestMapping("/order") public class OrderController { @Autowired private PurchaseOrderService purchaseOrderService; @GetMapping("/list") public String list(Model model) { QueryWrapper<PurchaseOrder> queryWrapper = new QueryWrapper<>(); queryWrapper.orderByDesc("create_time"); List<PurchaseOrder> orderList = purchaseOrderService.list(queryWrapper); model.addAttribute("orderList", orderList); return "order/list"; } @GetMapping("/add") public String addPage() { return "order/add"; } }

如果是前后端分离模式,可以把@Controller换成@RestController,页面交给 Vue 或 React 处理。本项目为降低学习成本,推荐使用 Thymeleaf 模板渲染。

4.7 前端页面简化示例

src/main/resources/templates/order/list.html中,使用 Thymeleaf 渲染订单列表:

<!DOCTYPE html> <html lang="zh" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>采购订单列表</title> <style> table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ccc; padding: 8px; text-align: center; } </style> </head> <body> <h2>采购订单列表</h2> <table> <thead> <tr> <th>订单编号</th> <th>供应商名称</th> <th>采购日期</th> <th>总金额</th> <th>状态</th> </tr> </thead> <tbody> <tr th:each="order : ${orderList}"> <td th:text="${order.orderNo}">PO202401010000</td> <td th:text="${order.supplierName}">XX供应商</td> <td th:text="${order.orderDate}">2024-01-01</td> <td th:text="${order.totalAmount}">0.00</td> <td th:text="${order.status == 0 ? '待审核' : order.status == 1 ? '已审核' : order.status == 2 ? '已入库' : '已取消'}">待审核</td> </tr> </tbody> </table> </body> </html>

这里的th:each是 Thymeleaf 的循环语法,功能类似 JSP 的c:forEach。状态字段通过三元表达式转换为中文,这种方式简单直观。

5. 完整业务流程:订单审核与入库

单纯做增删改查还不够,采购管理系统最核心的业务闭环是“审核 → 入库 → 更新库存”。下面补上这个关键流程。

5.1 订单审核逻辑

文件路径:com/example/purchase/service/impl/PurchaseOrderServiceImpl.java中追加方法:

@Override @Transactional(rollbackFor = Exception.class) public void auditOrder(Long orderId) { PurchaseOrder order = this.getById(orderId); if (order == null) { throw new RuntimeException("订单不存在"); } if (order.getStatus() != 0) { throw new RuntimeException("只有待审核状态的订单才能审核"); } order.setStatus(1); this.updateById(order); }

这种写法体现了状态校验的逻辑。如果直接无条件更新状态,很容易出现“已入库订单又被审核”的并发问题。实际开发中,还可以用乐观锁或状态条件更新来保证并发安全。

5.2 入库操作与库存更新

入库操作涉及两张表的修改:采购订单状态更新、商品库存增加。这两步必须放在同一个事务中。

@Override @Transactional(rollbackFor = Exception.class) public void stockIn(Long orderId) { PurchaseOrder order = this.getById(orderId); if (order == null) { throw new RuntimeException("订单不存在"); } if (order.getStatus() != 1) { throw new RuntimeException("只有已审核状态的订单才能入库"); } // 查询订单明细 QueryWrapper<PurchaseOrderItem> itemQuery = new QueryWrapper<>(); itemQuery.eq("order_id", orderId); List<PurchaseOrderItem> items = purchaseOrderItemMapper.selectList(itemQuery); // 更新商品库存 for (PurchaseOrderItem item : items) { Product product = productMapper.selectById(item.getProductId()); if (product == null) { throw new RuntimeException("商品不存在:" + item.getProductName()); } int newStock = product.getStockQuantity() + item.getQuantity(); product.setStockQuantity(newStock); productMapper.updateById(product); } // 更新订单状态为已入库 order.setStatus(2); this.updateById(order); }

这段代码体现了两个高频面试考点:事务的一致性和业务状态校验。当面试官问“库存怎么保证不超卖”时,你可以顺着这个逻辑讲解。

6. 运行项目与验证

6.1 初始化数据库

在 MySQL 中执行前面提供的建表 SQL,并把连接信息改成自己的账号密码。建议执行以下命令确认表结构:

SHOW TABLES;

确保能看到supplierproductpurchase_orderpurchase_order_itemsys_user五张表。

6.2 启动项目

在 IDEA 中运行启动类PurchaseApplication.java,启动类代码如下:

package com.example.purchase; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class PurchaseApplication { public static void main(String[] args) { SpringApplication.run(PurchaseApplication.class, args); } }

控制台出现以下日志说明启动成功:

Tomcat started on port(s): 8080 (http) with context path '' Started PurchaseApplication in 2.5 seconds (process running for 2.8)

浏览器访问:

http://localhost:8080/order/list

如果能看到订单列表页面,说明项目已经跑通。

6.3 接口自测

如果你把 Controller 改成了前后端分离模式,可以用 Postman 或 curl 自测接口。以查询订单列表为例:

curl http://localhost:8080/api/order/list

返回 JSON 示例:

{ "code": 200, "data": [ { "id": 1, "orderNo": "PO20240615103000", "supplierName": "上海华兴电子", "totalAmount": 35600.00, "status": 1 } ] }

如果开启了我的 MyBatis SQL 日志,控制台会打印出执行的 SQL 语句,配合日志能快速定位 SQL 问题。

7. 常见问题与排查思路

初学者在搭建和运行 SpringBoot 项目时,大概率会遇到下面这些问题。我整理了出现频率最高的几类,对应给出解决思路。

问题现象常见原因解决思路
java: invalid source release: 17IDEA 未配置 JDK17 编译环境检查 Project Structure 中的 SDK 和 Language Level,调为 17
Failed to configure a DataSource数据库配置缺失或连接失败检查application.yml的 url、用户名、密码,确认 MySQL 已启动
Access denied for user 'root'@'localhost'密码错误或权限不足核对数据库密码;为项目单独创建最小权限账号
Unknown database 'purchase_system'数据库未提前创建在 MySQL 中执行CREATE DATABASE purchase_system
启动报ClassNotFoundException: jakarta.servlet.*Spring Boot 3 与旧版 Tomcat/JSP 依赖冲突不要引入javax.servlet旧包,统一使用 jakarta 依赖
Port 8080 was already in use8080 端口被其他进程占用换端口,在 yml 中修改 server.port;或查找占用进程并关闭
Maven 依赖下载慢网络问题或未配置国内镜像配置阿里云 Maven 镜像,检查 idea 代理设置
SQL 语句没有打印MyBatis 日志配置缺失确认mybatis-plus.configuration.log-impl配置为 StdOutImpl

下面针对几个问题展开细说。

7.1 端口被占用

这是最常见的启动失败问题。在 Windows 下可以使用命令查找占用进程:

netstat -ano | findstr 8080

通过最后一列的 PID,打开任务管理器找到对应进程并结束。如果不想结束进程,最简单的方式是修改端口:

server: port: 8081

7.2 JDK 版本不匹配

有些同学电脑上同时存在 JDK8 和 JDK17,IDEA 仍然默认使用旧版本。解决办法:

  1. 点击菜单File → Project Structure → SDKs,添加 JDK17 路径。
  2. 点击Project,把 Project SDK 和 Language Level 都改为 17。
  3. Modules中确认每个模块的 Language Level 也是 17。
  4. 检查 Maven 的pom.xmljava.version是否设置为 17。

7.3 SpringBoot 版本太高导致依赖不兼容

如果代码里使用了 MyBatis-Plus 旧版启动器,Spring Boot 3 启动时会报:

Invalid value type for attribute 'factoryBeanObjectType': java.lang.String

解决办法:将mybatis-plus-boot-starter换成mybatis-plus-spring-boot3-starter,版本使用 3.5.3 以上。

8. 最佳实践与工程建议

8.1 简历上如何写这个项目

很多同学项目做完了,但简历写得跟“仓库目录说明书”一样,这是很吃亏的。比如这样写,面试官看了也不会留下印象:

采购管理系统,使用 SpringBoot + MyBatis + MySQL,实现了供应商、订单、商品的管理。

建议改成“问题导向 + 技术亮点”的写法:

采购管理系统 技术栈:SpringBoot 3.2 / JDK17 / MyBatis-Plus / MySQL 8.0 / Thymeleaf 负责内容: 1. 设计供应商、采购订单、订单明细、商品库存等 5 张核心表,并通过外键冗余方式优化报表查询性能。 2. 基于 MyBatis-Plus 实现订单主表和明细表批量保存,使用 @Transactional 保证订单创建、审核、入库流程的数据一致性。 3. 实现订单状态机(待审核 → 已审核 → 已入库),在审核和入库接口中加入状态校验,避免非法状态流转。 4. 使用 HikariCP 连接池,配置 SQL 日志,解决 MySQL 连接超时与慢查询定位问题。

这种写法有数据量、有技术点、有业务设计,面试官问起来你也有话可讲。

8.2 项目迭代建议

如果时间充裕,可以继续给项目增加亮点:

  • Redis 缓存:使用 Spring Data Redis 缓存供应商列表,降低数据库压力。
  • Spring Security:把登录功能升级为基于 JWT 的认证授权。
  • 异步处理:订单创建成功后发送通知消息,使用 Spring 的事件机制或 MQ。
  • Excel 导出:使用 EasyExcel 导出采购订单报表。
  • 接口文档:集成 Knife4j 或 SpringDoc,自动生成 Swagger 接口文档。

8.3 数据库操作安全底线

在做这个项目时,要养成好习惯:

  • 删除数据前先备份,生产环境不要随便执行DELETE FROM
  • 更新操作必须带 WHERE,避免全表更新。
  • 数据库账号遵循最小权限原则,项目连接用户只授予需要的数据库权限。
  • 密码明文存储只适合教学项目,真实项目必须使用 BCrypt 等加密算法。

9. 总结与下一步学习方向

本文围绕采购管理系统这个完整的 JavaWeb 项目,讲清楚了从环境准备到代码实现的整条链路。核心内容包括:

  • JDK17 安装与 SpringBoot 3.x 的版本关系。
  • 供应商表、订单表、明细表、商品表、用户表的数据库设计。
  • SpringBoot 项目的三层架构代码组织方式。
  • 事务控制、状态流转、库存更新的业务实现。
  • 常见启动报错的排查思路。
  • 简历项目描述的优化技巧。

这个项目做下来,你至少能收获一份可运行、可演示、可讲解的完整代码,这也是春招秋招简历上比较实用的储备。建议你拿到代码后,不要只满足于“跑起来”,而是自己重新写一遍订单审核和入库的逻辑,尝试改 bug、加功能,只有亲手踩过坑,面试时才能讲得深入。

如果你的目标是进后端开发岗,下一步可以继续学习 Spring Security 权限控制、Redis 缓存、消息队列、Docker 部署这些方向。从“能跑”到“能上生产”,中间差的不是某个复杂框架,而是一整套工程化思维。

如果你在搭建过程中遇到了本文没有覆盖的报错,欢迎评论区带上完整日志提问,我看到后会及时回复,也会把高频问题补充进后续的排错文章中。收藏本文,动手实践,这是最快掌握 SpringBoot 开发的方式。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/27 10:18:03

FCC认证BLE模块AMB2621开发实战:从硬件设计到认证合规

1. 项目概述与模块选型思考 1.1 FCC-Certified AMB2621 Bluetooth Smart Module 到底是什么 做硬件这行久了&#xff0c;你会发现一个很有意思的现象&#xff1a;很多刚入行的工程师拿到一个蓝牙模块&#xff0c;第一反应是翻datasheet看引脚定义、看AT指令集、看电流参数&…

作者头像 李华
网站建设 2026/8/27 10:17:55

组合数计算全攻略:从原理到实战的决策框架与避坑指南

1. 项目概述&#xff1a;为什么我们需要“一张图全解组合数”&#xff1f; 组合数&#xff0c;这个在高中数学课本里就出现的概念&#xff0c;对很多人来说&#xff0c;可能就停留在 C(n, m) 这个符号和 n! / (m! * (n-m)!) 这个公式上。当年考试&#xff0c;背下来、会算&…

作者头像 李华
网站建设 2026/8/27 10:17:18

基于SpringBoot的面试刷题平台系统的设计与实现毕业设计项目源码

温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台…

作者头像 李华
网站建设 2026/8/27 10:16:25

蓝桥杯国赛CB组真题深度解析:从算法思维到实战技巧

1. 从“刷题”到“破局”&#xff1a;深度复盘2022蓝桥杯国赛CB组真题又到了备赛季&#xff0c;看着手边一沓沓的真题&#xff0c;你是不是也感觉陷入了“刷题-遗忘-再刷题”的循环&#xff1f;特别是像蓝桥杯国赛这种级别的竞赛&#xff0c;题目早已超越了基础语法的考查&…

作者头像 李华
网站建设 2026/8/27 10:13:10

MATLAB数据处理:从算数思维到建模思维的工程化实践

1. 从“算数”到“建模”&#xff1a;MATLAB数据处理的核心思维转变 很多刚开始接触数学建模的同学&#xff0c;拿到MATLAB的第一反应往往是&#xff1a;这不就是个高级计算器吗&#xff1f;输入几个数&#xff0c;调用几个函数&#xff0c;得出结果。这种想法在应对简单作业时…

作者头像 李华
网站建设 2026/8/27 10:12:43

iOS 应用提审全流程解析:从证书配置到审核被拒排查

处理 iOS 应用提审&#xff0c;很多团队把它当成“最后一步”的打包上传操作。实际上&#xff0c;真正影响提审结果的工作分布在开发者账号、证书、构建打包、App Store Connect 元数据、审核回复这条完整链条上。任何一环出错&#xff0c;都会出现“上传成功但审核被拒”这类结…

作者头像 李华