Commit eda05387 authored by lining's avatar lining

feat: 换绑手机

parent 4b3031b8
......@@ -74,6 +74,13 @@ public class RandomUtils {
return (int) ((Math.random() * 9 + 1) * 100000);
}
/**
* length 位数验证码, 例: 014871 127845 ...
*/
public static String getRandomCode(int length) {
return "" + (int) ((Math.random() * 9 + 1) * Math.pow(10, length <= 4 ? 3 : (length - 1)));
}
/**
* 获取固定长度随机数
*
......
......@@ -8,9 +8,15 @@ public class RedisKeyConstants {
/**
* 短信更换绑定手机码
*/
public static final String SMS_BIND_CODE = "sms:bind_code";
public static final String SMS_BIND_CODE = "sms:re_bind_code";
/**
* 行政单位区域树
*/
public static final String BASE_AREA_TREE = "base:area_tree";
public static final String CHECK_CODE_KEY = "code:%s:%s";
public static final int CODE_EXPIRED = 10 * 60 * 1000;
}
......@@ -11,6 +11,13 @@ import lombok.Getter;
*/
public enum BizCodeEnum {
/**
* 验证码分组
*/
CODE_LIMITED("验证码发送过快"),
CODE_ERROR("验证码错误"),
/**
* 订单分组
*/
......
package com.onsiteservice.constant.enums;
/**
* <P></P>
*
* @author lining
* @version v1.0
* @since 2022/4/12 18:07
*/
public enum SendCodeEnum {
REBIND_PHONE
}
package com.onsiteservice.miniapp.controller.user;
import com.onsiteservice.common.annotation.user.CurrentUserId;
import com.onsiteservice.core.result.Result;
import com.onsiteservice.miniapp.controller.user.dto.BindPhoneDTO;
import com.onsiteservice.miniapp.controller.user.dto.SendCodeDTO;
import com.onsiteservice.miniapp.service.user.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.NonNull;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author 李宁
* @date 2022-07-13 14:44
*/
@Api(tags = "用户模块")
@RestController
@RequestMapping("/user")
@Validated
public class UserController {
@Resource
private UserService userService;
@ApiOperation(value = "绑定手机发送验证码", notes = "作者: 李宁")
@PostMapping("send_code")
public Result<String> sendCode(@RequestBody @NonNull @Validated SendCodeDTO dto) {
return userService.sendCode(dto);
}
@ApiOperation(value = "换绑手机", notes = "作者: 李宁")
@PostMapping("rebind")
public Result<String> rebindPhone(@RequestBody @NonNull @Validated BindPhoneDTO dto, @CurrentUserId Long userId) {
return userService.rebindPhone(dto, userId);
}
}
package com.onsiteservice.miniapp.controller.user.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
/**
* <P></P>
*
* @author 李宁
* @version v1.0
* @since 2022/7/15 10:51
*/
@Data
@ApiModel("绑定手机请求模型")
public class BindPhoneDTO {
@ApiModelProperty(value = "验证码")
@NotBlank(message = "验证码")
private String code;
@ApiModelProperty(value = "手机号")
@NotBlank(message = "请输入手机号")
@Pattern(regexp = "^1[3456789]\\d{9}$", message = "手机号格式不正确")
private String phone;
}
package com.onsiteservice.miniapp.controller.user.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
/**
* <P></P>
*
* @author 李宁
* @version v1.0
* @since 2022/7/15 10:51
*/
@Data
@ApiModel("发送验证码请求模型")
public class SendCodeDTO {
@ApiModelProperty(value = "发送的手机号")
@NotBlank(message = "请输入手机号")
@Pattern(regexp = "^1[3456789]\\d{9}$", message = "手机号格式不正确")
private String to;
}
package com.onsiteservice.miniapp.service.user;
import com.onsiteservice.constant.constant.RedisKeyConstants;
import com.onsiteservice.constant.enums.BizCodeEnum;
import com.onsiteservice.constant.enums.SendCodeEnum;
import com.onsiteservice.core.exception.ServiceException;
import com.onsiteservice.core.result.Result;
import com.onsiteservice.core.result.ResultGenerator;
import com.onsiteservice.dao.common.AbstractMapper;
import com.onsiteservice.dao.mapper.user.UserMapper;
import com.onsiteservice.entity.user.User;
import com.onsiteservice.miniapp.controller.user.dto.BindPhoneDTO;
import com.onsiteservice.miniapp.controller.user.dto.SendCodeDTO;
import com.onsiteservice.util.RandomUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class UserService extends AbstractMapper<User> {
@Autowired
private StringRedisTemplate redisTemplate;
@Resource
private UserMapper userMapper;
public Result<String> sendCode(SendCodeDTO dto) {
log.info("user sendCode dto: {}", dto);
String cacheKey = String.format(RedisKeyConstants.CHECK_CODE_KEY, SendCodeEnum.REBIND_PHONE.name(), dto.getTo());
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
// 重复发送逻辑
if (StringUtils.isNotBlank(cacheValue)) {
long ttl = Long.parseLong(cacheValue.split("_")[1]);
if ((System.currentTimeMillis() - ttl) < 60 * 1000) {
throw new ServiceException(BizCodeEnum.CODE_LIMITED);
}
}
String code = RandomUtils.generateNum(6);
String value = code + "_" + System.currentTimeMillis();
log.info("user sendCode phone: {}, code: {}", dto.getTo(), code);
// 置入
redisTemplate.opsForValue().set(cacheKey, value, RedisKeyConstants.CODE_EXPIRED, TimeUnit.MILLISECONDS);
// TODO 发送短信
return ResultGenerator.success();
}
public Result<String> rebindPhone(BindPhoneDTO dto, Long userId) {
log.info("user rebindPhone dto: {}, userId: {}", dto, userId);
boolean f = checkCode(SendCodeEnum.REBIND_PHONE, dto.getPhone(), dto.getCode());
if (!f) {
throw new ServiceException(BizCodeEnum.CODE_ERROR);
}
User user = User.builder().id(userId).phone(dto.getPhone()).build();
return userMapper.updateByPrimaryKeySelective(user) == 1 ? ResultGenerator.success() : ResultGenerator.fail("换绑失败");
}
/**
* 验证 code
*/
public boolean checkCode(SendCodeEnum sendCodeEnum, String to, String code) {
String cacheKey = String.format(RedisKeyConstants.CHECK_CODE_KEY, sendCodeEnum.name(), to);
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
if (StringUtils.isNotBlank(cacheValue)) {
String cacheCode = cacheValue.split("_")[0];
if (cacheCode.equalsIgnoreCase(code)) {
// 删除验证码
redisTemplate.delete(cacheKey);
return true;
}
}
return false;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment