Vendored
+3
-3
@@ -23,8 +23,8 @@
|
||||
" * @author ${1:}",
|
||||
" * @version V1.0",
|
||||
" * @title ${TM_FILENAME_BASE}",
|
||||
" * @description ${2:}",
|
||||
" * @date ${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE} ${CURRENT_HOUR}:${CURRENT_MINUTE}",
|
||||
" * @description ${2:}",
|
||||
" */",
|
||||
""
|
||||
],
|
||||
@@ -38,8 +38,8 @@
|
||||
" * @author ${1:}",
|
||||
" * @version V1.0",
|
||||
" * @title ${TM_FILENAME_BASE}",
|
||||
" * @description ${2:}",
|
||||
" * @date ${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE} ${CURRENT_HOUR}:${CURRENT_MINUTE}",
|
||||
" * @description ${2:}",
|
||||
" */",
|
||||
""
|
||||
],
|
||||
@@ -53,8 +53,8 @@
|
||||
" * @author ${1:}",
|
||||
" * @version V1.0",
|
||||
" * @title ${TM_FILENAME_BASE}",
|
||||
" * @description ${2:}",
|
||||
" * @date ${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE} ${CURRENT_HOUR}:${CURRENT_MINUTE}",
|
||||
" * @description ${2:}",
|
||||
" */",
|
||||
""
|
||||
],
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
<flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
|
||||
<jansi.version>1.18</jansi.version>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<guava.version>33.0.0-jre</guava.version>
|
||||
<hutool.version>5.8.26</hutool.version>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
</properties>
|
||||
|
||||
<!-- 统一依赖管理 -->
|
||||
@@ -146,6 +149,25 @@
|
||||
<artifactId>jansi</artifactId>
|
||||
<version>${jansi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.jy.xiaoyishu.auth.constant;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ayi
|
||||
* @version V1.0
|
||||
* @title RedisKeyConstants
|
||||
* @description Redis key 常量
|
||||
* @date 2026/01/15 18:45
|
||||
*/
|
||||
|
||||
public class RedisKeyConstants {
|
||||
|
||||
/**
|
||||
* 验证码 KEY 前缀
|
||||
*/
|
||||
private static final String VERIFICATION_CODE_KEY_PREFIX = "verification_code:";
|
||||
|
||||
/**
|
||||
* 构建验证码 KEY
|
||||
*
|
||||
* @param phone 手机号
|
||||
* @return 验证码 KEY
|
||||
*/
|
||||
public static String buildVerificationCodeKey(String phone) {
|
||||
return VERIFICATION_CODE_KEY_PREFIX + phone;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.jy.framework.biz.operationlog.aspect.ApiOperationLog;
|
||||
import com.jy.framework.common.response.Response;
|
||||
import com.jy.xiaoyishu.auth.vo.User;
|
||||
import com.jy.xiaoyishu.auth.model.vo.User;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.jy.xiaoyishu.auth.controller;
|
||||
|
||||
import com.jy.framework.biz.operationlog.aspect.ApiOperationLog;
|
||||
import com.jy.framework.common.response.Response;
|
||||
import com.jy.xiaoyishu.auth.model.vo.verificationcode.SendVerificationCodeReqVO;
|
||||
import com.jy.xiaoyishu.auth.service.VerificationCodeService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author ayi
|
||||
* @version V1.0
|
||||
* @title VerificationCodeController
|
||||
* @date 2026/01/15
|
||||
* @description 验证码控制器
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class VerificationCodeController {
|
||||
@Resource
|
||||
private VerificationCodeService verificationCodeService;
|
||||
|
||||
@PostMapping("/verification/code/send")
|
||||
@ApiOperationLog(description = "发送短信验证码")
|
||||
public Response<?> send(@Validated @RequestBody SendVerificationCodeReqVO sendVerificationCodeReqVO) {
|
||||
return verificationCodeService.send(sendVerificationCodeReqVO);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ import com.jy.framework.common.exception.BaseExceptionInterface;
|
||||
@AllArgsConstructor
|
||||
public enum ResponseCodeEnum implements BaseExceptionInterface {
|
||||
// -------- 通用异常状态码 --------
|
||||
SYSTEM_ERROR("AUTH-10000", "系统错误"), PARAM_NOT_VALID("AUTH-10001", "参数错误");
|
||||
SYSTEM_ERROR("AUTH-10000", "系统错误"),
|
||||
PARAM_NOT_VALID("AUTH-10001", "参数错误"),
|
||||
VERIFICATION_CODE_SEND_FREQUENTLY("AUTH-20000", "请求太频繁,请3分钟后再试");
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
|
||||
@@ -15,6 +15,15 @@ import com.jy.xiaoyishu.auth.enums.ResponseCodeEnum;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ayi
|
||||
* @version V1.0
|
||||
* @title GlobalExceptionHandler
|
||||
* @description 全局异常处理器
|
||||
* @date 2026/01/15 18:40
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@ControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.jy.xiaoyishu.auth.vo;
|
||||
package com.jy.xiaoyishu.auth.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.jy.xiaoyishu.auth.model.vo.verificationcode;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ayi
|
||||
* @version V1.0
|
||||
* @title SendVerificationCodeReqVO
|
||||
* @description 发送验证码请求参数
|
||||
* @date 2026/01/15 18:39
|
||||
*/
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SendVerificationCodeReqVO {
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
private String phone;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.jy.xiaoyishu.auth.service;
|
||||
|
||||
import com.jy.framework.common.response.Response;
|
||||
import com.jy.xiaoyishu.auth.model.vo.verificationcode.SendVerificationCodeReqVO;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ayi
|
||||
* @version V1.0
|
||||
* @title VerificationCodeService
|
||||
* @description 验证码服务
|
||||
* @date 2026/01/15 18:48
|
||||
*/
|
||||
|
||||
public interface VerificationCodeService {
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
*
|
||||
* @param sendVerificationCodeReqVO 发送验证码请求参数
|
||||
* @return 响应结果
|
||||
*/
|
||||
Response<?> send(SendVerificationCodeReqVO sendVerificationCodeReqVO);
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.jy.xiaoyishu.auth.service.impl;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import com.jy.framework.common.exception.BizException;
|
||||
import com.jy.framework.common.response.Response;
|
||||
import com.jy.xiaoyishu.auth.constant.RedisKeyConstants;
|
||||
import com.jy.xiaoyishu.auth.enums.ResponseCodeEnum;
|
||||
import com.jy.xiaoyishu.auth.model.vo.verificationcode.SendVerificationCodeReqVO;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.jy.xiaoyishu.auth.service.VerificationCodeService;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class VerificationCodeServiceImpl implements VerificationCodeService {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Override
|
||||
public Response<?> send(SendVerificationCodeReqVO sendVerificationCodeReqVO) {
|
||||
// 手机号
|
||||
String phone = sendVerificationCodeReqVO.getPhone();
|
||||
|
||||
// 构建验证码 redis key
|
||||
String key = RedisKeyConstants.buildVerificationCodeKey(phone);
|
||||
|
||||
// 判断是否已发送验证码
|
||||
boolean isSent = redisTemplate.hasKey(key);
|
||||
if (isSent) {
|
||||
// 若之前发送的验证码未过期,则提示发送频繁
|
||||
throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_SEND_FREQUENTLY);
|
||||
}
|
||||
|
||||
// 生成 6 位随机数字验证码
|
||||
String verificationCode = RandomUtil.randomNumbers(6);
|
||||
|
||||
// todo: 调用第三方短信发送服务
|
||||
|
||||
log.info("==> 手机号: {}, 已发送验证码:【{}】", phone, verificationCode);
|
||||
|
||||
// 存储验证码到 redis, 并设置过期时间为 3 分钟
|
||||
redisTemplate.opsForValue().set(key, verificationCode, 3, TimeUnit.MINUTES);
|
||||
|
||||
return Response.success();
|
||||
}
|
||||
}
|
||||
@@ -55,9 +55,9 @@ spring:
|
||||
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
min-idle: 0 # 连接池中的最小空闲连接
|
||||
max-idle: 10 # 连接池中的最大空闲连接
|
||||
# output:
|
||||
# ansi:
|
||||
# enabled: always
|
||||
output:
|
||||
ansi:
|
||||
enabled: always
|
||||
application:
|
||||
name: xiaoyishu-auth
|
||||
|
||||
|
||||
@@ -57,6 +57,22 @@
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类 -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
Reference in New Issue
Block a user