diff --git a/.vscode/java.code-snippets b/.vscode/java.code-snippets index 3abd9b7..4c23945 100644 --- a/.vscode/java.code-snippets +++ b/.vscode/java.code-snippets @@ -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:}", " */", "" ], diff --git a/pom.xml b/pom.xml index 5fbbcc2..f515d32 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,9 @@ 1.5.0 1.18 1.38.0 + 33.0.0-jre + 5.8.26 + 3.12.0 @@ -146,6 +149,25 @@ jansi ${jansi.version} + + + + com.google.guava + guava + ${guava.version} + + + + cn.hutool + hutool-all + ${hutool.version} + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + diff --git a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/constant/RedisKeyConstants.java b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/constant/RedisKeyConstants.java new file mode 100644 index 0000000..d797d30 --- /dev/null +++ b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/constant/RedisKeyConstants.java @@ -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; + } + +} diff --git a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/controller/TestController.java b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/controller/TestController.java index 747b9e4..0160916 100644 --- a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/controller/TestController.java +++ b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/controller/TestController.java @@ -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; diff --git a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/controller/VerificationCodeController.java b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/controller/VerificationCodeController.java new file mode 100644 index 0000000..16582d5 --- /dev/null +++ b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/controller/VerificationCodeController.java @@ -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); + } +} diff --git a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/enums/ResponseCodeEnum.java b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/enums/ResponseCodeEnum.java index e6b6096..f462bfb 100644 --- a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/enums/ResponseCodeEnum.java +++ b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/enums/ResponseCodeEnum.java @@ -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分钟后再试"); /** * 错误码 diff --git a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/exception/GlobalExceptionHandler.java b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/exception/GlobalExceptionHandler.java index 34111b1..aba80d9 100644 --- a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/exception/GlobalExceptionHandler.java +++ b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/exception/GlobalExceptionHandler.java @@ -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 { diff --git a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/vo/User.java b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/model/vo/User.java similarity index 94% rename from xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/vo/User.java rename to xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/model/vo/User.java index b6ec884..02d92df 100644 --- a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/vo/User.java +++ b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/model/vo/User.java @@ -1,4 +1,4 @@ -package com.jy.xiaoyishu.auth.vo; +package com.jy.xiaoyishu.auth.model.vo; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/model/vo/verificationcode/SendVerificationCodeReqVO.java b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/model/vo/verificationcode/SendVerificationCodeReqVO.java new file mode 100644 index 0000000..b705cf9 --- /dev/null +++ b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/model/vo/verificationcode/SendVerificationCodeReqVO.java @@ -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; + +} diff --git a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/service/VerificationCodeService.java b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/service/VerificationCodeService.java new file mode 100644 index 0000000..27446b7 --- /dev/null +++ b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/service/VerificationCodeService.java @@ -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); + +} diff --git a/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/service/impl/VerificationCodeServiceImpl.java b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/service/impl/VerificationCodeServiceImpl.java new file mode 100644 index 0000000..5f53cdc --- /dev/null +++ b/xiaoyi-auth/src/main/java/com/jy/xiaoyishu/auth/service/impl/VerificationCodeServiceImpl.java @@ -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 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(); + } +} diff --git a/xiaoyi-auth/src/main/resources/config/application-dev.yml b/xiaoyi-auth/src/main/resources/config/application-dev.yml index 1bc8e41..175eb32 100644 --- a/xiaoyi-auth/src/main/resources/config/application-dev.yml +++ b/xiaoyi-auth/src/main/resources/config/application-dev.yml @@ -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 diff --git a/xiaoyi-framework/xiaoyi-common/pom.xml b/xiaoyi-framework/xiaoyi-common/pom.xml index b2aaa50..ed09ea0 100644 --- a/xiaoyi-framework/xiaoyi-common/pom.xml +++ b/xiaoyi-framework/xiaoyi-common/pom.xml @@ -57,6 +57,22 @@ org.hibernate.validator hibernate-validator + + + + com.google.guava + guava + + + + cn.hutool + hutool-all + + + + org.apache.commons + commons-lang3 + \ No newline at end of file