Skip to content

sgahch/hmdp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

黑马点评 (HMDP) - 本地生活服务平台

基于Spring Boot + Redis + RabbitMQ的高性能本地生活服务平台,类似大众点评的功能实现

GitHub 贡献贪吃蛇

📋 项目概述

黑马点评是一个完整的本地生活服务平台,提供商铺查询、优惠券秒杀、用户社交、博客分享等功能。项目重点展示了Redis缓存、RabbitMQ消息队列、分布式锁等技术在实际业务场景中的应用,并针对高并发场景进行了深度优化。

🆕 最新更新

  • 用户体验大幅提升:
    • 新增专门的头像上传接口,支持文件选择和自动更新
    • 修复用户信息更新后前端不显示的问题
    • 完善Redis缓存同步机制,确保数据一致性
  • 登录系统优化:
    • 修复登录时的NullPointerException问题
    • 修复登出时Redis Key错误删除的问题
    • 完善Token管理和会话处理
  • 消息队列升级: 从Redis Stream迁移到RabbitMQ,提升消息处理的可靠性和监控能力
  • 错误处理优化: 完善了Lua脚本的nil值检查和RabbitMQ的通道错误处理
  • 数据管理增强: 新增秒杀数据初始化和清理功能
  • 监控日志完善: 添加详细的调试日志,便于问题排查

🛠️ 技术栈

技术 版本 说明
后端框架
Spring Boot 2.7.4 主框架
MyBatis Plus 3.5.2 ORM框架
Spring AMQP 2.7.4 RabbitMQ集成
数据存储
MySQL 8.0+ 关系型数据库
Redis 6.0+ 缓存数据库
消息队列
RabbitMQ 3.8+ 消息队列中间件
工具库
Hutool 5.8.8 Java工具库
Redisson 3.17.7 Redis分布式锁
Lombok 1.18.30 代码简化

🎯 核心功能模块

1. 用户管理系统 ✨

  • 手机验证码登录: 基于Redis的验证码存储和校验,支持Token自动续期
  • 用户信息管理:
    • 用户资料编辑(昵称、个人介绍、性别、城市、生日)
    • 头像上传: 专门的头像上传接口,自动更新数据库和Redis缓存
    • 实时同步: 信息更新后前端立即显示,数据库与缓存保持一致
  • 会话管理: 完善的登录/登出机制,正确的Redis Key管理
  • 签到系统: 基于Redis BitMap的连续签到统计

2. 商铺管理系统

  • 商铺信息查询: 支持分类、地理位置查询
  • 缓存策略:
    • 缓存穿透解决方案(空值缓存)
    • 缓存雪崩解决方案(TTL随机化)
    • 缓存击穿解决方案(互斥锁、逻辑过期)

3. 优惠券秒杀系统 🔥

  • 秒杀功能: 高并发秒杀优惠券,支持库存预扣减
  • 分布式锁: 基于Redis + Redisson的分布式锁防止超卖
  • 异步处理: Lua脚本 + RabbitMQ消息队列优化性能
  • 一人一单: 防止用户重复下单,支持幂等性处理
  • 消息可靠性: RabbitMQ死信队列 + 重试机制保证消息不丢失
  • 数据管理: 自动初始化秒杀库存,清理过期数据

4. 博客社交系统

  • 博客发布: 用户可发布图文博客
  • 点赞功能: 基于Redis ZSet的点赞排行榜
  • 关注系统: 用户关注/取关,共同关注查询
  • Feed流: 基于推模式的关注用户博客推送

5. 地理位置服务

  • 附近商铺: 基于Redis GEO的地理位置查询
  • 距离计算: 自动计算用户与商铺的距离

📁 项目结构

hmdp/
├── src/main/java/com/hmdp/
│   ├── HmDianPingApplication.java          # 启动类
│   ├── config/                             # 配置类
│   │   ├── MvcConfig.java                  # MVC配置
│   │   ├── MybatisConfig.java              # MyBatis配置
│   │   ├── RedissonConfig.java             # Redisson配置
│   │   ├── RabbitMQConfig.java             # RabbitMQ配置
│   │   ├── UploadConfig.java               # 文件上传配置
│   │   └── WebExceptionAdvice.java         # 全局异常处理
│   ├── controller/                         # 控制器层
│   │   ├── BlogController.java             # 博客控制器
│   │   ├── FollowController.java           # 关注控制器
│   │   ├── ShopController.java             # 商铺控制器
│   │   ├── UserController.java             # 用户控制器
│   │   ├── VoucherController.java          # 优惠券控制器
│   │   └── VoucherOrderController.java     # 订单控制器
│   ├── dto/                                # 数据传输对象
│   │   ├── LoginFormDTO.java               # 登录表单
│   │   ├── Result.java                     # 统一返回结果
│   │   ├── ScrollResult.java               # 滚动分页结果
│   │   └── UserDTO.java                    # 用户信息
│   ├── entity/                             # 实体类
│   │   ├── Blog.java                       # 博客实体
│   │   ├── Follow.java                     # 关注关系
│   │   ├── Shop.java                       # 商铺实体
│   │   ├── User.java                       # 用户实体
│   │   ├── Voucher.java                    # 优惠券实体
│   │   └── VoucherOrder.java               # 订单实体
│   ├── interceptor/                        # 拦截器
│   │   ├── LoginInterceptor.java           # 登录拦截器
│   │   └── RefreshTokenInterceptor.java    # Token刷新拦截器
│   ├── mapper/                             # 数据访问层
│   │   ├── BlogMapper.java                 # 博客Mapper
│   │   ├── ShopMapper.java                 # 商铺Mapper
│   │   ├── UserMapper.java                 # 用户Mapper
│   │   └── VoucherOrderMapper.java         # 订单Mapper
│   ├── listener/                           # 消息监听器
│   │   └── SeckillOrderListener.java       # 秒杀订单消息监听器
│   ├── service/                            # 服务接口层
│   │   ├── IBlogService.java               # 博客服务接口
│   │   ├── IShopService.java               # 商铺服务接口
│   │   ├── IUserService.java               # 用户服务接口
│   │   ├── IVoucherOrderService.java       # 订单服务接口
│   │   ├── MessageProducerService.java     # 消息生产者服务接口
│   │   └── SeckillDataInitService.java     # 秒杀数据初始化服务接口
│   ├── service/impl/                       # 服务实现层
│   │   ├── BlogServiceImpl.java            # 博客服务实现
│   │   ├── ShopServiceImpl.java            # 商铺服务实现
│   │   ├── UserServiceImpl.java            # 用户服务实现
│   │   ├── VoucherOrderServiceImpl.java    # 订单服务实现
│   │   ├── MessageProducerServiceImpl.java # 消息生产者服务实现
│   │   └── SeckillDataInitServiceImpl.java # 秒杀数据初始化服务实现
│   └── utils/                              # 工具类
│       ├── CacheClient.java                # 缓存工具类
│       ├── ILock.java                      # 分布式锁接口
│       ├── SimpleRedisLock.java            # Redis分布式锁实现
│       ├── RedisIdWorker.java              # Redis ID生成器
│       ├── RedisConstants.java             # Redis常量
│       └── UserHolder.java                 # 用户上下文
├── src/main/resources/
│   ├── application.yaml                    # 应用配置
│   ├── mapper/                             # MyBatis映射文件
│   ├── seckill.lua                         # 秒杀Lua脚本(已优化nil值检查)
│   └── unlock.lua                          # 解锁Lua脚本
├── hmdp.sql                                # 数据库脚本
├── rabbitmq-setup.md                       # RabbitMQ安装指南
└── pom.xml                                 # Maven配置

🚀 快速启动

环境要求

  • JDK 11+
  • Maven 3.6+
  • MySQL 8.0+
  • Redis 6.0+
  • RabbitMQ 3.8+ (推荐使用Docker)

启动步骤

  1. 克隆项目
git clone <repository-url>
cd hmdp
  1. 数据库初始化
# 创建数据库
mysql -u root -p
CREATE DATABASE hmdp;

# 导入数据
mysql -u root -p hmdp < hmdp.sql
  1. 配置文件 修改 src/main/resources/application.yaml:
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/hmdp
    username: your_username
    password: your_password
  redis:
    host: localhost
    port: 6379
    password: your_redis_password  # 如果有密码
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  1. 启动Redis
redis-server
  1. 启动RabbitMQ
# 使用Docker(推荐)
docker run -d --name rabbitmq \
  -p 5672:5672 \
  -p 15672:15672 \
  -e RABBITMQ_DEFAULT_USER=guest \
  -e RABBITMQ_DEFAULT_PASS=guest \
  rabbitmq:3-management

# 或者直接启动(如果已安装)
rabbitmq-server
  1. 初始化秒杀数据
# 启动应用后,初始化秒杀券库存
curl -X POST http://localhost:8081/voucher-order/init/all
  1. 运行项目
mvn spring-boot:run
  1. 访问应用

🔧 核心技术特性

Redis应用场景

功能 Redis数据结构 应用场景
用户登录 Hash 存储验证码和用户Token,支持用户信息缓存
用户信息缓存 Hash 缓存用户基本信息,支持实时更新同步
商铺缓存 String 缓存商铺信息,解决缓存穿透/击穿/雪崩
点赞排行 ZSet 博客点赞用户排序
关注列表 Set 存储用户关注关系,计算共同关注
签到统计 BitMap 用户连续签到天数统计
附近商铺 GEO 地理位置查询
秒杀库存 String + Lua 原子性库存扣减(已优化nil值检查)
分布式锁 String + Lua 防止并发问题
Feed流 ZSet 关注用户博客时间线
消息去重 String 防止RabbitMQ消息重复处理

RabbitMQ消息队列

组件 说明 特性
秒杀订单队列 seckill.order.queue 处理秒杀订单异步创建
死信队列 seckill.order.dlx.queue 处理失败消息,支持人工介入
消息重试 自动重试机制 最多重试3次,失败后进入死信队列
消息确认 手动ACK 确保消息处理成功后才确认
幂等处理 Redis去重 防止消息重复处理

分布式锁实现

  • 基于Redis的SET NX EX命令
  • Lua脚本保证原子性
  • 自动续期机制(Redisson)
  • 防止锁误删除

缓存策略

  • 缓存穿透: 空值缓存 + 布隆过滤器
  • 缓存击穿: 互斥锁 + 逻辑过期
  • 缓存雪崩: TTL随机化 + 多级缓存

秒杀系统架构

用户请求 → Lua脚本(库存检查) → RabbitMQ队列 → 异步处理 → 数据库
    ↓              ↓                ↓           ↓
  参数校验      原子性操作        消息持久化    订单入库
    ↓              ↓                ↓           ↓
  返回结果      防止超卖          重试机制     完成订单

秒杀流程优化:

  1. 预检查: Lua脚本原子性检查库存和用户资格
  2. 异步处理: RabbitMQ解耦,提升响应速度
  3. 可靠性保证: 消息持久化 + 死信队列 + 重试机制
  4. 幂等性: Redis去重 + 分布式锁防止重复处理

🎯 API接口说明

用户管理接口

接口 方法 说明
/user/code POST 发送手机验证码
/user/login POST 手机验证码登录
/user/logout POST 用户登出
/user/me GET 获取当前用户信息
/user/update PUT 更新用户基本信息(昵称等)
/user/info/update PUT 更新用户详细信息(城市、介绍等)
/user/avatar/upload POST 头像上传(文件上传+数据库更新)
/user/info/{id} GET 获取用户详细信息
/user/sign POST 用户签到
/user/sign/count GET 获取签到统计

秒杀相关接口

接口 方法 说明
/voucher-order/seckill/{id} POST 秒杀优惠券
/voucher-order/init/{voucherId} POST 初始化单个秒杀券库存
/voucher-order/init/all POST 批量初始化所有秒杀券库存
/voucher-order/clean/expired POST 清理过期秒杀数据

调试接口

接口 方法 说明
/shop/debug/types GET 查看商铺类型分布
/shop/debug/geo/{typeId} GET 检查Redis GEO数据
/shop/init/geo POST 初始化商铺地理位置数据
/upload/debug/config GET 检查文件上传配置

📚 学习资源

本项目来自黑马程序员Redis教程,并进行了深度优化:

项目分支说明

  • master: 完整版代码,包含RabbitMQ优化和错误修复
  • init: 初始化代码,适合跟着教程学习开发

🌟 技术亮点

1. 高并发秒杀系统

  • QPS优化: 通过Redis预检查 + 异步处理,支持万级QPS
  • 超卖防护: Lua脚本原子性操作 + 分布式锁双重保障
  • 用户体验: 快速响应,异步处理订单创建

2. 消息队列可靠性

  • 消息持久化: RabbitMQ确保消息不丢失
  • 重试机制: 自动重试3次,失败进入死信队列
  • 监控告警: 通过管理界面实时监控队列状态

3. 缓存架构优化

  • 多级缓存: 本地缓存 + Redis缓存
  • 缓存一致性: 更新策略 + 过期时间控制
  • 性能监控: 详细的缓存命中率统计

4. 用户体验优化 ✨

  • 头像上传: 一键上传,自动更新数据库和缓存,前端实时显示
  • 信息同步: 用户信息更新后立即同步到Redis缓存和前端显示
  • 会话管理: 完善的登录状态管理,Token自动续期
  • 错误处理: 友好的错误提示和异常处理机制

5. 系统稳定性

  • 错误处理: 完善的异常处理和降级策略
  • 日志监控: 详细的业务日志和性能指标
  • 数据管理: 自动化的数据初始化和清理
  • 缓存一致性: 数据库更新与Redis缓存实时同步

📊 性能指标

指标 数值 说明
秒杀QPS 10,000+ Redis + RabbitMQ异步处理
响应时间 <100ms Lua脚本快速预检查
消息处理 99.9%+ RabbitMQ可靠性保证
缓存命中率 95%+ 多级缓存策略

📞 联系方式

如有问题,请参考原教程或提交Issue。

🏆 致谢

感谢黑马程序员提供的优秀教程,本项目在原有基础上进行了深度优化和扩展。

1.下载

克隆完整项目

git clone https://github.com/sgahch/hmdp.git

切换分支

git checkout init

2.常见问题

Q1: RabbitMQ连接失败

错误: Connection refusedAMQP connection error

解决方案:

# 检查RabbitMQ是否启动
docker ps | grep rabbitmq

# 如果未启动,执行启动命令
docker run -d --name rabbitmq \
  -p 5672:5672 \
  -p 15672:15672 \
  rabbitmq:3-management

Q2: 秒杀时提示"秒杀活动未开始或已结束"

错误码: 返回错误码3

解决方案:

# 初始化秒杀券库存
curl -X POST http://localhost:8081/voucher-order/init/all

# 或初始化单个秒杀券
curl -X POST http://localhost:8081/voucher-order/init/{voucherId}

Q3: Redis Lua脚本错误

错误: attempt to compare nil with number

解决方案: 已在最新版本中修复,确保使用最新的seckill.lua脚本

Q4: 图片上传失败

错误: 上传目录不存在

解决方案: 检查nginx目录配置,确保路径正确

# 检查上传配置
curl http://localhost:8081/upload/debug/config

Q5: 地理位置查询无结果

解决方案: 初始化商铺地理位置数据

curl -X POST http://localhost:8081/shop/init/geo

Q6: 用户登录后信息更新不显示

错误: 更新昵称或头像后前端不显示最新信息

解决方案:

  1. 检查Redis缓存是否正常工作
  2. 确保使用最新版本的代码(已修复缓存同步问题)
  3. 清除浏览器缓存并重新登录

Q7: 头像上传失败

错误: "头像上传失败"或文件上传错误

解决方案:

# 检查上传目录权限
ls -la nginx-1.18.0/html/hmdp/imgs/

# 确保目录存在且可写
mkdir -p nginx-1.18.0/html/hmdp/imgs/
chmod 755 nginx-1.18.0/html/hmdp/imgs/

Q8: 登录时出现NullPointerException

错误: 登录过程中空指针异常

解决方案: 已在最新版本中修复,确保UserDTO中的字段正确处理null值

About

黑马点评-第二版本(引入消息队列rabbitmq+功能完善)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors