# 注册接口优化总结 ## 🎯 优化目标 简化用户注册流程,仅需要手机号、密码和短信验证码即可完成注册。 ## ✅ 完成的优化 ### 1. 简化RegisterRequest **文件**: `backend-single/src/main/java/com/emotion/dto/request/RegisterRequest.java` **修改前**:需要账号、密码、确认密码、用户名、昵称、邮箱、手机号、图形验证码等多个字段 **修改后**:仅需3个字段 ```java @Data @EqualsAndHashCode(callSuper = true) public class RegisterRequest extends BaseRequest { /** * 手机号(作为账号) */ @NotBlank(message = "手机号不能为空") @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") private String phone; /** * 密码 */ @NotBlank(message = "密码不能为空") @Size(min = 6, max = 20, message = "密码长度必须在6-20个字符之间") private String password; /** * 短信验证码 */ @NotBlank(message = "验证码不能为空") @Size(min = 6, max = 6, message = "验证码必须为6位") private String smsCode; } ``` ### 2. 新增SmsCodeResponse **文件**: `backend-single/src/main/java/com/emotion/dto/response/SmsCodeResponse.java` ```java @Data @Builder @NoArgsConstructor @AllArgsConstructor public class SmsCodeResponse { /** * 验证码(开发环境返回,生产环境不返回) */ private String code; /** * 过期时间(秒) */ private Long expiresIn; /** * 提示信息 */ private String message; } ``` ### 3. 新增获取短信验证码接口 **文件**: `backend-single/src/main/java/com/emotion/controller/AuthController.java` ```java /** * 获取短信验证码(用于注册) */ @GetMapping("/sms-code") @Operation(summary = "获取短信验证码", description = "用于注册时的短信验证码") public Result getSmsCode( @Parameter(description = "手机号", required = true) @RequestParam String phone) { SmsCodeResponse response = authService.sendSmsCode(phone); return Result.success("验证码已发送", response); } ``` **接口地址**: `GET /api/auth/sms-code?phone=13800138000` **响应示例**: ```json { "code": 200, "message": "验证码已发送", "data": { "code": "123456", "expiresIn": 300, "message": "验证码已发送,有效期5分钟" } } ``` ### 4. 优化注册接口逻辑 **文件**: `backend-single/src/main/java/com/emotion/service/impl/AuthServiceImpl.java` #### 4.1 新增常量定义 ```java private static final String SMS_CODE_PREFIX = "sms_code:"; private static final int SMS_CODE_EXPIRE_MINUTES = 5; private static final String DEFAULT_SMS_CODE = "123456"; ``` #### 4.2 简化注册逻辑 ```java @Override public AuthResponse register(RegisterRequest request) { // 1. 验证短信验证码 if (!validateSmsCode(request.getPhone(), request.getSmsCode())) { throw new CaptchaException("验证码错误或已过期"); } // 2. 检查手机号是否已存在 if (userService.getByPhone(request.getPhone()) != null) { throw new BusinessException("手机号已被注册"); } // 3. 生成随机用户名:开心 + 6位随机大小写字母和数字 String username = generateRandomUsername(); // 4. 使用手机号作为账号 String account = request.getPhone(); // 5. 创建用户 User user = userService.createUser( account, username, request.getPassword(), null, // 邮箱为空 request.getPhone() ); // 6. 生成令牌并返回 // ... } ``` #### 4.3 实现短信验证码发送 ```java @Override public SmsCodeResponse sendSmsCode(String phone) { // 验证手机号格式 if (!StringUtils.hasText(phone) || !phone.matches("^1[3-9]\\d{9}$")) { throw new BusinessException("手机号格式不正确"); } // 检查手机号是否已注册 if (existsByPhone(phone)) { throw new BusinessException("该手机号已被注册"); } // TODO: 接入真实的短信服务商(阿里云、腾讯云等) // 目前使用固定验证码 123456 String code = DEFAULT_SMS_CODE; // 将验证码存储到Redis,有效期5分钟 String key = SMS_CODE_PREFIX + phone; redisTemplate.opsForValue().set(key, code, SMS_CODE_EXPIRE_MINUTES, TimeUnit.MINUTES); log.info("发送短信验证码: phone={}, code={}", phone, code); // 构建响应 return SmsCodeResponse.builder() .code(code) // 开发环境返回验证码,生产环境应该删除此行 .expiresIn((long) SMS_CODE_EXPIRE_MINUTES * 60) .message("验证码已发送,有效期" + SMS_CODE_EXPIRE_MINUTES + "分钟") .build(); } ``` #### 4.4 实现短信验证码校验 ```java @Override public boolean validateSmsCode(String phone, String code) { if (!StringUtils.hasText(phone) || !StringUtils.hasText(code)) { return false; } String key = SMS_CODE_PREFIX + phone; String storedCode = (String) redisTemplate.opsForValue().get(key); if (storedCode == null) { log.warn("短信验证码不存在或已过期: phone={}", phone); return false; } boolean isValid = storedCode.equals(code); // 验证成功后删除验证码(一次性使用) if (isValid) { redisTemplate.delete(key); log.info("短信验证码验证成功: phone={}", phone); } else { log.warn("短信验证码错误: phone={}, expected={}, actual={}", phone, storedCode, code); } return isValid; } ``` #### 4.5 实现随机用户名生成 ```java /** * 生成随机用户名 * 格式:开心 + 6位随机大小写字母和数字 * * @return 随机用户名 */ private String generateRandomUsername() { String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuilder sb = new StringBuilder("开心"); for (int i = 0; i < 6; i++) { int index = random.nextInt(chars.length()); sb.append(chars.charAt(index)); } return sb.toString(); } ``` **用户名示例**: - 开心A3bC9z - 开心X7yK2m - 开心P1qW5n ### 5. 更新AuthService接口 **文件**: `backend-single/src/main/java/com/emotion/service/AuthService.java` 新增方法定义: ```java /** * 发送短信验证码 * * @param phone 手机号 * @return 短信验证码响应 */ SmsCodeResponse sendSmsCode(String phone); /** * 验证短信验证码 * * @param phone 手机号 * @param code 验证码 * @return 是否验证成功 */ boolean validateSmsCode(String phone, String code); ``` ## 📊 优化对比 | 项目 | 优化前 | 优化后 | |------|--------|--------| | 必填字段 | 账号、密码、确认密码、验证码、验证码key | 手机号、密码、短信验证码 | | 验证码类型 | 图形验证码 | 短信验证码 | | 用户名生成 | 手动输入或使用账号 | 自动生成(开心+6位随机) | | 账号 | 手动输入 | 自动使用手机号 | | 邮箱 | 可选输入 | 不需要 | | 昵称 | 可选输入 | 自动使用用户名 | ## 🔧 核心特性 ### 1. 简化注册流程 - ✅ 仅需3个字段:手机号、密码、短信验证码 - ✅ 自动生成用户名:开心 + 6位随机字符 - ✅ 手机号作为账号 - ✅ 移除了确认密码、邮箱、昵称等非必要字段 ### 2. 短信验证码机制 - ✅ 默认验证码:123456(开发环境) - ✅ 有效期:5分钟 - ✅ 一次性使用:验证成功后自动删除 - ✅ Redis存储:支持分布式部署 - ✅ TODO标记:预留真实短信服务接入点 ### 3. 安全性保障 - ✅ 手机号格式验证 - ✅ 手机号唯一性检查 - ✅ 验证码过期检查 - ✅ 验证码一次性使用 - ✅ 密码加密存储 ### 4. 用户体验优化 - ✅ 注册流程简单快捷 - ✅ 自动生成友好的用户名 - ✅ 清晰的错误提示 - ✅ 完整的API文档(Swagger) ## 🚀 使用示例 ### 1. 获取短信验证码 **请求**: ```bash curl -X GET "http://localhost:19089/api/auth/sms-code?phone=13800138000" ``` **响应**: ```json { "code": 200, "message": "验证码已发送", "data": { "code": "123456", "expiresIn": 300, "message": "验证码已发送,有效期5分钟" } } ``` ### 2. 用户注册 **请求**: ```bash curl -X POST "http://localhost:19089/api/auth/register" \ -H "Content-Type: application/json" \ -d '{ "phone": "13800138000", "password": "password123", "smsCode": "123456" }' ``` **响应**: ```json { "code": 200, "message": "注册成功", "data": { "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiresIn": 86400, "userInfo": { "id": "1844234567890123456", "account": "13800138000", "username": "开心A3bC9z", "nickname": "开心A3bC9z", "phone": "13800138000", "memberLevel": "free", "status": 1 }, "loginTime": "2025-10-06 21:49:33" } } ``` ## 📝 TODO事项 ### 1. 接入真实短信服务 **位置**: `AuthServiceImpl.sendSmsCode()` 方法 **当前代码**: ```java // TODO: 接入真实的短信服务商(阿里云、腾讯云等) // 目前使用固定验证码 123456 String code = DEFAULT_SMS_CODE; ``` **后续改进**: ```java // 生成随机6位数字验证码 String code = String.format("%06d", new Random().nextInt(1000000)); // 调用短信服务商API发送验证码 // 示例:阿里云短信服务 // smsService.sendSms(phone, code); ``` ### 2. 生产环境优化 **需要修改的地方**: 1. **移除响应中的验证码**: ```java return SmsCodeResponse.builder() // .code(code) // 生产环境删除此行 .expiresIn((long) SMS_CODE_EXPIRE_MINUTES * 60) .message("验证码已发送,有效期" + SMS_CODE_EXPIRE_MINUTES + "分钟") .build(); ``` 2. **添加发送频率限制**: - 同一手机号60秒内只能发送一次 - 同一IP每天最多发送10次 3. **添加验证码尝试次数限制**: - 同一手机号最多尝试5次 - 超过次数后需要重新获取验证码 ## ✅ 验证清单 - [x] 编译成功,无错误 - [x] RegisterRequest简化为3个字段 - [x] 新增SmsCodeResponse响应类 - [x] 新增获取短信验证码接口 - [x] 实现短信验证码发送逻辑 - [x] 实现短信验证码校验逻辑 - [x] 实现随机用户名生成 - [x] 优化注册接口逻辑 - [x] 添加Swagger API文档注解 - [x] 添加详细的日志记录 ## 🎉 总结 成功优化了注册接口,实现了以下目标: 1. ✅ **简化注册流程** - 仅需手机号、密码和短信验证码 2. ✅ **自动生成用户名** - 开心 + 6位随机大小写字母和数字 3. ✅ **短信验证码机制** - 默认123456,预留真实短信服务接入点 4. ✅ **完整的校验逻辑** - 手机号格式、唯一性、验证码有效性 5. ✅ **良好的代码质量** - 清晰的注释、完善的日志、标准的异常处理 现在用户可以通过简单的3步完成注册: 1. 输入手机号获取验证码 2. 输入密码和验证码 3. 自动生成用户名并完成注册 注册成功后自动登录,返回访问令牌和用户信息!