# inventory-order-system **Repository Path**: yechen653/inventory-order-system ## Basic Information - **Project Name**: inventory-order-system - **Description**: 库存订单单体系统, 用于加深自己的数据库理解 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-11-02 - **Last Updated**: 2026-11-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ims - 库存与订单系统 基于 Spring Boot + MyBatis + MySQL 的库存与订单后端服务,提供用户、商品、库存、订单四类资源的 RESTful 接口。 ## 技术基线 | 组件 | 版本 | 备注 | |---|---|---| | JDK | **21** | LTS;本地路径 `D:\SDK\java\jdk\jdk-21`(Temurin 21.0.9) | | Spring Boot | 3.5.7 | 命名空间为 `jakarta.*`,非 `javax.*` | | MyBatis Starter | 3.0.3 | | | MySQL | 8.0+ | 驱动坐标 `mysql-connector-j` | | Maven | 3.9+ | 运行时 JAVA_HOME 须指向 JDK 21 | > **JDK 版本一致性**:Maven、IDEA Project SDK、IDEA Run Configuration JRE 三处都应指向 JDK 21。 > `pom.xml` 的 `` 只控制编译期 `--release`,运行时用哪个 JVM 由启动方决定。 ## 数据库访问 连接串、账号、口令一律写在 `src/main/resources/application-local.yml`,该文件**不入库**。 首次使用: 1. 复制 `src/main/resources/application-local.yml.template` 为 `application-local.yml`,填入你的地址与口令; 2. `application-local.yml` 已在 `.gitignore` 中,不会被提交; 3. 执行 `sql/schema.sql` 建表。 ## 启动 ```bash mvn spring-boot:run # 冒烟:http://localhost:8080/api/hello ``` ## 接口文档(Swagger UI) 集成 springdoc-openapi 2.8.4,**运行时扫描 Spring MVC 映射自动生成**,新增接口无需手工维护文档。 | 用途 | 地址 | |---|---| | Swagger UI(可视化调试) | http://localhost:8080/swagger-ui/index.html | | OpenAPI JSON(可导入 Apifox / Postman) | http://localhost:8080/v3/api-docs | 两点说明: 1. 文档随应用启动才可访问,`mvn compile` 不会产出它; 2. 页面上的根路径(Server)由 `config/OpenApiConfig.java` 按 `server.port` 拼出, 若你以 `--server.port=8081` 启动,文档里的示例地址会自动跟着变。 > ⚠️ **生产环境不要无条件暴露**。对外部署时需按 profile 关闭(`springdoc.api-docs.enabled=false`)或加访问控制。 ## 目录结构 ``` src/main/java/com/yechen/ims ├── controller 接收 HTTP 请求,只做参数校验与转发 ├── service 业务逻辑(接口 + impl),事务边界所在 ├── mapper MyBatis 数据访问接口 ├── entity 与表一一对应,禁止直接作为出参 ├── dto 入参对象(含校验注解) ├── vo 出参对象,决定暴露什么 ├── common 统一返回 R、错误码、业务异常 └── config 全局异常处理等 src/main/resources/mapper Mapper XML(动态 SQL) sql/schema.sql 建表脚本(手工维护) ``` ## 接口清单 | 方法 | 路径 | 说明 | |---|---|---| | GET | `/api/hello` | 健康检查 | | GET | `/api/health/db` | 数据库连通性诊断(200 健康 / 503 不健康) | | POST | `/api/users/register` | 注册(bcrypt 哈希密码,手机号唯一) | | POST | `/api/users/login` | 登录(校验凭据) | | GET | `/api/users/{userId}` | 用户详情(不含密码哈希) | | PUT | `/api/users/{userId}` | 更新资料(仅 name / phone) | | POST | `/api/products` | 创建商品(同时初始化库存) | | GET | `/api/products/{id}` | 商品详情(含库存) | | GET | `/api/products?name=&status=` | 商品列表 | | PUT | `/api/products/{id}` | 部分字段更新 | | PATCH | `/api/products/{id}/status?status=` | 上架/下架 | | POST | `/api/orders` | 下单(创建订单+明细,扣库存) | | GET | `/api/orders/{orderId}` | 订单详情 | | GET | `/api/orders?userId=` | 用户订单列表 | | POST | `/api/orders/{orderId}/pay` | 支付(0→1) | | POST | `/api/orders/{orderId}/cancel` | 取消(0→2,回滚库存) | 订单状态为单向机,`0` 是唯一非终态:`0 待支付 → 1 已支付`、`0 → 2 已取消`、`0 → 3 已超时释放`。 所有流转都由条件更新(CAS,`WHERE order_status = 0`)抢占,抢不到的一方返回明确业务码: `5003 已支付` / `5004 已取消或已释放` / `5005 已过期`。超时未支付的订单由定时任务自动释放并归还库存, 不提供对应的 HTTP 接口。 下单接口支持幂等键 `requestId`:同一用户重复提交只会落一单,并返回同一个 `orderId`。 ## 设计说明 ### 库存模型 下单即扣减 `available_num`,`locked_num` 恒为 0。扣减为条件更新,不会出现超卖或负库存。 ### 无认证与鉴权 服务当前**没有任何认证机制**:`/api/users/{userId}` 可查看/修改任意用户,四个订单接口也不校验调用者身份。 登录接口只做凭据校验,**不签发令牌**,因此"登录成功"不产生任何后续访问权限——这一点容易误解,特此写明。 引入 JWT 时的改造方向:登录成功签发令牌 → 过滤器/拦截器校验令牌 → 从令牌中取当前用户ID (而非信任路径参数),并在服务层校验资源归属。 ### 密码与敏感信息 - 密码使用 **bcrypt**(`spring-security-crypto` 单模块,未引入完整 Spring Security)哈希后落库, 明文不写日志、不出服务层。选 bcrypt 而非 MD5/SHA 的理由见 `PasswordConfig`。 - 登录失败统一返回 `USER_PASSWORD_WRONG`,不区分"手机号不存在"与"密码错误"; 禁用账号的检查放在密码校验**之后**,避免通过差异化提示枚举账号。 - 出参一律用 VO,`User` 实体(含 `passwordHash`)不出服务层。 - **未经认证的接口会暴露用户手机号与余额**,属上述"无鉴权"已知限制的一部分。