智慧书城 — 项目业务价值点(已实现)
项目:
智慧书城(p3)
github地址: https://github.com/startmas/Model_Test
范围:当前已落地代码(认证 + 预约 + P0~P3)
用途:简历提炼、答辩讲解、面试准备、区分「RUD 堆砌」与「真实业务闭环」
最后更新:2026-07
一、文档说明
本文档回答一个问题:智慧书城项目目前已实现的部分,全部价值点在哪里?
与相关文档的分工:
| 文档 | 侧重 |
|---|---|
| [书城系统功能规划] | 全量需求与后续路线 |
| [书城系统分阶段实施指南] | 分阶段任务清单 |
| [预约系统业务价值点] | 预约模块深度展开 |
| [P2签到业务流程与技术栈] | 签到流程与 Redis 设计 |
二、一句话结论
这个项目最有价值的不是「功能多」,而是形成了一条 可演示、可讲清楚、有技术深度 的业务闭环:
登录 → 预约座位 → 到馆扫码签到 → 连续 7 天赠券 → 浏览图书 → 用券余额购书
↘ 申请借阅 → 管理员确认 → 归还
普通分页、CRUD 是配套能力;并发控制、状态机、缓存、跨模块规则联动 才是值得写进简历和面试里讲的部分。
三、已实现模块一览
| 模块 | 包路径 | 已实现能力 |
|---|---|---|
| 统一认证 | com.zx.auth | 密码/邮箱/手机验证码、QQ OAuth、JWT 双 Token、RBAC、限流 |
| 座位预约 | com.zx.reservation | 选座预约、行锁防超卖、取消释放、管理端生成座位/时段 |
| 图书目录 | com.zx.bookstore.catalog | 分类、上架、详情 Redis Cache-Aside |
| 到馆签到 | com.zx.marketing.checkin | 每日场馆码、预约联动、BitMap 连签、满 7 天发券 |
| 优惠券 | com.zx.bookstore.coupon | 连签发券、门槛校验、购书抵扣、核销 |
| 购书交易 | com.zx.bookstore.trade | 下单算价、余额支付、库存扣减、幂等 |
| 图书借阅 | com.zx.bookstore.borrow | 申请、审核、归还、占用册数校验 |
四、价值分层总览
| 层级 | 内容 | 简历/答辩权重 |
|---|---|---|
| ⭐⭐⭐ 核心亮点 | 座位防超卖、签到 BitMap、购书事务、借阅占用、认证安全 | 必讲 |
| ⭐⭐ 完整度 | 三级资源模型、Cache-Aside、状态机、幂等、模块化错误码、RBAC 复用 | 补充 |
| ⭐ 基础能力 | 分页列表、CRUD、管理后台、Demo 数据初始化 | 一带而过 |
五、跨模块联动价值
这是项目比「七个独立 Demo」更强的地方:
认证 JWT/RBAC ──→ 所有业务接口统一鉴权
预约 BOOKED ──→ 签到校验「今日有预约、场馆一致、在时段内」
签到连签 7 天 ──→ 优惠券 CHECKIN_7 自动发放
优惠券 ──→ 购书下单抵扣 payAmount
图书 saleStock ──→ 购书支付扣减
图书 borrowStock + 占用数 ──→ 借阅申请校验
用户 balance ──→ 购书支付扣款;/api/user/me 展示
管理端 ADMIN ──→ 生成座位/时段、签到码、审核借阅、标记预约完成
六、分模块价值点详解
6.1 统一认证(com.zx.auth)
⭐⭐⭐ 核心亮点
| 价值点 | 说明 |
|---|---|
| JWT 双 Token | Access 短效访问 API;Refresh 长效续期,减少频繁登录 |
| Refresh Rotation | 每次刷新发放新 Token 对,旧 Session 作废,降低泄露风险 |
| 重放检测 | 使用已撤销的 Refresh Token 会触发全 Session 撤销 |
| 会话绝对上限 | 默认 90 天,滑动续期不突破首次登录起的绝对过期 |
| 多种登录 | 密码、邮箱验证码、手机验证码、QQ PC 扫码 OAuth |
| 安全限流 | 发码 60s/小时/IP 限制;连续登录失败 5 次锁定 15 分钟(Redis) |
⭐⭐ 完整度
| 价值点 | 说明 |
|---|---|
| RBAC | USER / ADMIN,@PreAuthorize 贯穿预约、图书、签到、交易 |
| 验证码仅存 Redis | 哈希存储,响应不返回明文;邮箱走 SMTP |
| 自动注册 | 验证码登录时用户不存在则自动创建并绑定 identity |
| Logout 双路径 | Access 有效时拉黑 jti;过期时仍可用 Refresh 撤销 Session |
| QQ OAuth | state 防 CSRF;回调后 302 到前端 hash 传 Token(需配置后启用) |
⭐ 基础能力
GET /api/user/me返回 id、username、roles、balance- BCrypt 密码哈希、统一
ApiResponse响应格式
6.2 座位预约(com.zx.reservation)
模块深度展开见 预约系统业务价值点
⭐⭐⭐ 核心亮点
(1)座位粒度防超卖
1. SELECT ... FROM reservation_seat WHERE id = ? FOR UPDATE ← 行级锁
2. 校验 (time_slot_id, seat_id) 是否已有 BOOKED 订单
3. 事务内 INSERT reservation_order
4. 失败 → 3011「该座位在该时段已被预约」
- 库存模型:时段 × 座位,不是粗粒度「还剩 3 个名额」
- 可演示:两人同时抢 A03,仅一人成功
(2)业务规则链(创建预约前按序校验)
| 规则 | 错误码 | 含义 |
|---|---|---|
| 时段/座位有效 | 3001 / 3010 | 基础校验 |
| 自习室启用 | 3007 | 下架不可约 |
| 时段未过期 | 3009 | 开始时间 > 当前 |
| 同时段不重复约 | 3003 | 用户该时段仅 1 单 BOOKED |
| 每日上限 | 3006 | BOOKED+COMPLETED < 2 |
| 座位未被占用 | 3011 | 防超卖 |
(3)预约单状态机
BOOKED ──取消──→ CANCELLED(释放座位占用)
BOOKED ──完成──→ COMPLETED(座位视为已消费)
canTransitTo()显式拒绝非法跳转 → 3004- 取消:本人或 ADMIN;完成:仅 ADMIN
(4)幂等创建
- 请求带
idempotencyKey→ 已存在则直接返回原订单,不重复 INSERT - 与 3003 区别:幂等防「同一请求重试」;3003 防「用户主动约两次」
⭐⭐ 完整度
| 价值点 | 说明 |
|---|---|
| 三级资源模型 | 自习室 → 座位(rowNum/colNum)→ 时段 → 预约单 |
| 两种剩余展示 | 时段级 remainingSeats;座位级 available(可渲染座位 Grid) |
| 取消即释放 | 改状态为 CANCELLED,占用由订单状态实时推导,无需手动改计数 |
| 管理端闭环 | 创建资源、批量生成座位/时段、全部订单、标记完成 |
| 签到码接口 | GET .../checkin-code 为签到模块提供每日场馆码 |
| 认证复用 | 用户/管理接口分角色;user_id 关联 auth_user |
| Demo 数据 | ReservationDemoDataInitializer 启动时生成座位与时段 |
⭐ 基础能力
- 自习室分页列表、我的预约、预约详情、资源 CRUD
6.3 图书目录(com.zx.bookstore.catalog)
⭐⭐⭐ 核心亮点
| 价值点 | 说明 |
|---|---|
| Cache-Aside | 详情先 Redis,miss 查 MySQL 再回填 |
| 更新失效 | 改书/下架 evict book:detail:{id},防脏读 |
| 防雪崩 | TTL 1800s + random(0~300s),避免大量 key 同时过期 |
⭐⭐ 完整度
| 价值点 | 说明 |
|---|---|
| 双库存字段 | saleStock(购书)、borrowStock(借阅),同一书目分流 |
| 分类管理 | 启用分类列表、管理端新建分类、重名校验 |
| 逻辑下架 | DELETE 置 status=0,列表/详情不可见 |
⭐ 基础能力
- 分页列表、按分类/关键字筛选、管理端上架/更新
6.4 到馆签到(com.zx.marketing.checkin)
流程细节见 P2签到业务流程与技术栈
⭐⭐⭐ 核心亮点
(1)预约联动签到——不是无门槛按钮签到
| 规则 | 错误码 |
|---|---|
| 场馆每日码有效 | 4310 |
| 今日未重复签到 | 4301 |
| 有今日 BOOKED 预约 | 4302 |
| 预约单存在且属本人 | 4309 / 4312 |
| 预约场馆与扫码场馆一致 | 4311 |
| 预约日期为今日 | 4303 |
| 在可签到窗口内 | 4308 |
| 该预约未签到过 | 4304 |
(2)Redis 数据结构设计
| Key | 用途 |
|---|---|
venue:checkin:code:{venueId}:{date} | 每日场馆码,TTL 到当日结束 |
sign:user:{userId}:{yyyyMM} | BitMap,每位表示当月某天是否签到 |
sign:streak:{userId} | 连续签到天数 |
sign:last:{userId} | 上次签到日期,断签判断 |
(3)连签赠券
- 连续 7 天 → 同步发放
CHECKIN_7优惠券 → streak 归零 - 写
checkin_record、更新预约checkin_at、Redis BitMap 与 streak 同事务后更新
⭐⭐ 完整度
| 价值点 | 说明 |
|---|---|
| eligible 预检 | 扫码后先查可签预约列表,前端友好 |
| 签到日历 API | GET /calendar?month= 返回已签日期列表 |
| 管理端签到码 | 返回 checkinUrl,前端用 qrcode 生成二维码 |
| 跨模块协作 | 依赖 reservation 订单状态;触发 coupon 发券 |
⭐ 基础能力
GET /streak查询当前连续天数
6.5 优惠券(com.zx.bookstore.coupon)
⭐⭐⭐ 核心亮点
| 价值点 | 说明 |
|---|---|
| 连签自动发券 | 签到满 7 天触发,无需用户手动领取 |
| 门槛校验 | 下单时校验 thresholdAmount,未达门槛 4103 |
| 抵扣算价 | calculateDiscount 计算 discountAmount 与 payAmount |
| 支付核销 | markUsed 防重复使用,关联订单 ID |
⭐⭐ 完整度
| 价值点 | 说明 |
|---|---|
| 券状态 | UNUSED / USED / EXPIRED |
| 获得方式记录 | obtainWay 如 CHECKIN_7,便于运营追溯 |
| 模板机制 | coupon_template + user_coupon 分离 |
⭐ 基础能力
GET /api/coupons/mine?status=我的优惠券列表
6.6 购书交易(com.zx.bookstore.trade)
⭐⭐⭐ 核心亮点
支付事务(TradeService.pay)
1. 校验订单归属与状态 PENDING_PAY
2. FOR UPDATE 锁图书 → deductSaleStock(可售库存)
3. FOR UPDATE 锁用户 → deductBalance(余额扣减)
4. markPaid(乐观状态流转,防重复支付)
5. couponService.markUsed(优惠券核销)
- 任一步失败,
@Transactional整体回滚 - 典型电商「下单 → 支付」模型,可对接真实支付渠道
下单幂等
idempotencyKey重复提交返回同一订单
⭐⭐ 完整度
| 价值点 | 说明 |
|---|---|
| 主子表 | trade_order + trade_order_item |
| 算价清晰 | totalAmount / discountAmount / payAmount 分离 |
| 取消未支付单 | PENDING_PAY → CANCELLED |
| 余额展示 | /api/user/me 的 balance,默认 100.00 |
⭐ 基础能力
- 我的订单列表/详情、单本图书下单(quantity 默认 1)
6.7 图书借阅(com.zx.bookstore.borrow)
⭐⭐⭐ 核心亮点
| 价值点 | 说明 |
|---|---|
| 占用册数建模 | countOccupiedByBookId < borrowStock,不是简单减库存 |
| 一人一本 | hasActiveBorrowByUser → 有未还书不可再借(4003) |
| 行锁申请 | findByIdForUpdate 锁图书行后校验占用 |
| 状态机 | APPLIED → CONFIRMED → RETURNED / CANCELLED / REJECTED |
⭐⭐ 完整度
| 价值点 | 说明 |
|---|---|
| 审核流程 | 用户申请 → 管理员 confirm / reject |
| 双向归还 | 用户 return 或管理员 adminReturn |
| 应还日期 | 确认借出后计算 dueAt(基于图书 borrowDays) |
| 权限隔离 | 4007 无权操作他人借阅单 |
⭐ 基础能力
- 我的借阅列表/详情、管理端全部借阅单查询
七、工程技术价值(横向)
7.1 四层架构一致
Controller → Service → Repository → Mapper/Entity
各模块(auth、reservation、bookstore、checkin)均遵循同一分层,便于维护与答辩讲解。
7.2 模块化异常与错误码
| 模块 | 码段 | Handler |
|---|---|---|
| 认证 | 1001–1002、2001–2006、3001(403) | 统一鉴权 |
| 预约 | 3001–3011 | ReservationExceptionHandler |
| 图书 | 4001、4005 | BookstoreExceptionHandler |
| 借阅 | 4002–4007 | BorrowExceptionHandler |
| 优惠券 | 4101–4104 | CouponExceptionHandler |
| 购书 | 4201–4206 | TradeExceptionHandler |
| 签到 | 4301–4312 | CheckinExceptionHandler |
| QQ OAuth | 5001 | QqOAuthController |
前端可按码段统一 Toast、刷新座位图、跳转登录等。
7.3 并发与一致性手段汇总
| 场景 | 手段 |
|---|---|
| 预约抢座 | MySQL FOR UPDATE + 占用校验 |
| 购书支付 | FOR UPDATE + 条件更新库存/余额 |
| 借阅申请 | FOR UPDATE + 占用计数 |
| 签到连签 | Redis 原子更新 + MySQL 签到记录 |
| 重复提交 | idempotencyKey(预约、购书) |
| 重复支付 | markPaid 乐观状态流转 |
7.4 Redis 使用汇总
| 用途 | Key 模式 |
|---|---|
| 会话/Token | Refresh Session、Access 黑名单 |
| 验证码 | 哈希存储 + TTL |
| 限流 | 发码间隔、登录失败计数 |
| 图书缓存 | book:detail:{id} |
| 签到码 | venue:checkin:code:{venueId}:{date} |
| 签到 BitMap | sign:user:{userId}:{yyyyMM} |
| 连签 | sign:streak:{userId}、sign:last:{userId} |
7.5 已落地状态机一览
| 实体 | 状态 | 关键流转 |
|---|---|---|
| 预约单 | BOOKED / CANCELLED / COMPLETED | 取消释放占用;完成消费座位 |
| 借阅单 | APPLIED / CONFIRMED / RETURNED / CANCELLED / REJECTED | 审核、归还 |
| 购书单 | PENDING_PAY / PAID / CANCELLED | 支付扣库存余额;取消未支付 |
八、与普通 CRUD 项目的区别
| 普通项目 | 本项目已实现 |
|---|---|
| 能增删改查 | 能演示并发抢座、余额支付事务 |
| 登录就完事 | 双 Token + Rotation + 限流 + 多方式登录 |
| 签到按钮 +1 | 预约联动 + 场馆码 + BitMap + 连签发券 |
| 下单 INSERT | 库存 + 余额 + 优惠券同一事务 |
| 借书减库存 | 占用册数 + 审核状态机 |
| 各模块孤立 | 预约 → 签到 → 券 → 购书 完整链路 |
九、答辩演示脚本(约 3 分钟)
1. admin 登录(展示 roles 含 ADMIN)
2. 管理端:生成座位、生成今日时段
3. 用户预约今日 A03 座 → 成功 orderNo + seatNo
4. (可选)并发抢同一座 → 3011
5. 管理端获取 checkin-code → 展示二维码
6. 用户扫码 → eligible → 签到成功,streak +1
7. 浏览图书详情(第二次命中 Redis 缓存)
8. 创建购书订单 → 选优惠券 → 余额支付 → balance 减少
9. (可选)申请借阅 → admin 确认 → 归还
十、简历写法
项目名称:智慧书城综合业务平台
项目描述(示例):
基于 Spring Boot 的智慧书城后端,已完成统一认证、座位预约、到馆签到、借购书与优惠券模块。实现座位级行锁防超卖与完整业务规则链;签到采用 Redis BitMap 记录连签并联动预约履约,满 7 天自动发券;购书在同一事务内完成库存扣减、余额支付与优惠券核销;借阅模块通过占用册数建模与状态机管理审核归还流程。
技术关键词:
Spring Boot · JWT 双 Token · Redis BitMap · MySQL 行锁 · Cache-Aside · 状态机 · RBAC · 幂等
只讲 2 个最深的技术点(时间紧时):
- 座位级防超卖:
FOR UPDATE+(slot_id, seat_id)占用 + 3011 - 跨模块闭环:预约 → 签到 BitMap → 发券 → 购书事务支付
十一、面试高频追问
| 追问 | 回答要点 |
|---|---|
| 怎么防超卖? | 预约:座位 FOR UPDATE + 占用校验;购书:deductSaleStock;借阅:countOccupied |
| 签到为什么用 BitMap? | 按月存 31 bit,省空间;calendar 接口批量 getBit |
| 连签断了怎么办? | 比较 sign:last,非连续则 streak 重置为 1 |
| 支付如何保证一致? | @Transactional,库存/余额/券核销同成功或同回滚 |
| 幂等怎么做的? | 预约/购书:idempotencyKey UNIQUE,存在则返回原单 |
| 缓存怎么保证一致性? | Cache-Aside + 写时 evict;TTL 加随机偏移防雪崩 |
| 和秒杀有什么区别? | 当前券仅连签发;高并发抢券为后续规划 |
| Refresh Token 被盗怎么办? | Rotation + 重放检测撤销全 Session;Access 短效 |
十二、相关代码索引
| 模块 | 核心类 |
|---|---|
| 认证 | AuthService、JwtService、AuthRedisService、QqOAuthService |
| 预约 | ReservationService、ReservationOrderStatus、ReservationSeatMapper |
| 图书 | BookCatalogService、BookRedisService |
| 签到 | CheckinService、CheckinRedisService |
| 优惠券 | CouponService |
| 购书 | TradeService |
| 借阅 | BorrowService |

552

被折叠的 条评论
为什么被折叠?



