1. 项目概述:黑马点评与短信登录功能
黑马点评是一个典型的Java Web实战项目,常用于Java后端学习者的技能训练。这个项目模拟了类似大众点评的业务场景,包含商户管理、用户评价、优惠券发放等核心功能模块。其中短信登录作为现代应用的标配功能,既考验开发者对第三方API的调用能力,也涉及会话管理、安全验证等关键技术点。
我选择从零开始搭建这个项目,一方面是考虑到很多初学者在导入已有项目时经常遇到依赖缺失、配置错误等问题;另一方面是因为短信登录功能的实现过程中有许多值得注意的细节,比如验证码的有效期管理、接口防刷机制等。通过这个实战,你将掌握:
- 如何正确导入Maven项目并解决常见依赖问题
- 基于Redis的短信验证码存储方案
- 分布式会话管理的实现方式
- 接口安全防护的常规手段
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 开发环境准备与项目导入
2.1 基础环境配置
在开始项目之前,请确保你的开发环境满足以下要求:
- JDK 17(推荐使用Amazon Corretto版本)
- IntelliJ IDEA 2023.x(社区版或旗舰版)
- Maven 3.8+
- Redis 6.2+
- MySQL 8.0
注意:项目中使用Lombok简化代码,需要在IDEA中安装Lombok插件并启用注解处理(Settings → Build → Compiler → Annotation Processors)
2.2 项目导入步骤详解
- 从GitHub克隆项目源码:
bash复制git clone https://github.com/heima-black/comment-demo.git
-
在IntelliJ IDEA中选择"Open"而非"Import",直接指向项目根目录下的pom.xml文件。这种方式能让IDEA更好地识别Maven项目结构。
-
等待依赖下载完成后,检查以下关键配置:
application.yml中的数据库连接信息redis.properties中的Redis服务器配置sms.properties中的短信平台账号配置
-
执行数据库初始化脚本(通常位于
src/main/resources/db目录下)
常见问题排查:
- 如果出现"源发行版17需要目标发行版17"错误,检查以下位置:
- File → Project Structure → Project SDK和Language level
- Settings → Build → Java Compiler → Target bytecode version
- 遇到Lombok不生效的情况,尝试:
- 清理并重新构建项目(Build → Rebuild Project)
- 检查是否启用了注解处理
3. 短信登录功能实现解析
3.1 整体架构设计
短信登录的业务流程可以分为三个核心阶段:
-
验证码获取阶段:
- 用户输入手机号请求验证码
- 服务端生成随机6位数字
- 通过第三方短信平台发送
- 验证码存入Redis(设置2分钟有效期)
-
登录验证阶段:
- 用户提交手机号和验证码
- 服务端比对Redis中的验证码
- 验证成功后生成登录令牌
-
会话维持阶段:
- 使用Token作为身份凭证
- 采用Redis存储用户会话信息
- 通过拦截器实现权限校验
3.2 核心代码实现
验证码生成与发送:
java复制@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private ISmsService smsService;
@PostMapping("/code")
public Result sendCode(@RequestParam String phone) {
// 1. 生成6位随机验证码
String code = RandomUtil.randomNumbers(6);
// 2. 保存到Redis,2分钟有效
stringRedisTemplate.opsForValue().set(
"login:code:" + phone,
code,
2, TimeUnit.MINUTES);
// 3. 发送短信(实际项目应使用异步方式)
smsService.sendVerificationCode(phone, code);
return Result.ok();
}
}
登录验证逻辑:
java复制@PostMapping("/login")
public Result login(@RequestBody LoginFormDTO loginForm) {
// 1. 校验验证码
String cacheCode = stringRedisTemplate.opsForValue().get(
"login:code:" + loginForm.getPhone());
if (cacheCode == null || !cacheCode.equals(loginForm.getCode())) {
return Result.fail("验证码错误或已过期");
}
// 2. 查询用户(不存在则自动注册)
User user = query().eq("phone", loginForm.getPhone()).one();
if (user == null) {
user = createUserWithPhone(loginForm.getPhone());
}
// 3. 生成Token并保存用户信息到Redis
String token = UUID.randomUUID().toString(true);
UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
stringRedisTemplate.opsForHash().putAll(
"login:token:" + token,
BeanUtil.beanToMap(userDTO));
stringRedisTemplate.expire(
"login:token:" + token,
30, TimeUnit.MINUTES);
// 4. 删除已使用的验证码
stringRedisTemplate.delete("login:code:" + loginForm.getPhone());
return Result.ok(token);
}
3.3 安全防护措施
-
接口防刷:
- 对
/user/code接口添加限流(如1分钟1次) - 使用Redis记录手机号最近发送时间
java复制// 在sendCode方法开始处添加限流判断 String lastSendTime = stringRedisTemplate.opsForValue() .get("login:code:limit:" + phone); if (lastSendTime != null && System.currentTimeMillis() - Long.parseLong(lastSendTime) < 60000) { return Result.fail("发送过于频繁,请稍后再试"); } - 对
-
Token续期:
- 每次访问需要登录的接口时,延长Token有效期
- 通过拦截器实现自动续期
-
敏感信息保护:
- 返回给前端的UserDTO应过滤掉password等敏感字段
- Redis中的用户信息也应做适当脱敏处理
4. 常见问题与优化方案
4.1 典型问题排查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 验证码发送失败 | 短信平台配置错误 | 检查sms.properties中的账号、签名信息 |
| Redis连接超时 | Redis服务未启动或配置错误 | 确认Redis服务器状态和连接参数 |
| 登录后获取不到用户信息 | Token未正确传递 | 检查前端是否在header中添加Authorization |
| 接口响应缓慢 | Redis或数据库连接池不足 | 调整连接池大小(如HikariCP配置) |
4.2 性能优化建议
-
异步发送短信:
- 使用Spring的@Async注解或消息队列(如RabbitMQ)
- 避免因短信平台响应慢导致接口超时
-
Redis管道化操作:
- 对多个Redis命令使用pipeline减少网络开销
- 特别适用于登录时保存用户信息和设置过期时间
-
二级缓存策略:
- 对用户基本信息可添加本地缓存(Caffeine)
- 设置合理的过期时间(如5分钟)
4.3 扩展功能思路
-
多端登录管理:
- 在Redis中记录设备信息
- 实现同账号多设备登录控制
-
验证码图形化:
- 添加图形验证码作为前置验证
- 使用Kaptcha等库生成
-
登录日志审计:
- 记录登录时间、IP、设备等信息
- 用于异常登录检测
在实际开发中,短信登录看似简单,但要做到生产环境可用,需要考虑各种边界情况和安全问题。我在多个项目中实现过类似功能,发现最常见的坑是:
- 验证码有效期设置不合理(太短影响体验,太长不安全)
- 未做接口防刷导致被恶意消耗短信额度
- Token续期逻辑有缺陷导致用户频繁掉线
建议在正式上线前,至少进行以下测试:
- 并发登录测试(如JMeter模拟100并发)
- 验证码暴力破解测试
- Token失效场景测试
