0


用户微服务用户注册功能实现

文章目录

用户注册之前需要先给注册的手机号发送一条验证码,我们把验证码存储在Redis中。

发送的时候我们先把验证码存储到Redis,然后用户发起注册的时候取出验证。

在这里插入图片描述
image.png

发送验证码

Redis配置如下:

packagecom.zjq.users.config;importcom.fasterxml.jackson.annotation.JsonAutoDetect;importcom.fasterxml.jackson.annotation.PropertyAccessor;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.redis.connection.RedisConnectionFactory;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;importorg.springframework.data.redis.serializer.StringRedisSerializer;/**
 * redis配置类
 * @author zjq
 */@ConfigurationpublicclassRedisTemplateConfiguration{/**
     * redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
     * @param redisConnectionFactory
     * @return
     */@BeanpublicRedisTemplate<Object,Object>redisTemplate(RedisConnectionFactory redisConnectionFactory){RedisTemplate<Object,Object> redisTemplate =newRedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);// 使用Jackson2JsonRedisSerialize 替换默认序列化Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =newJackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper =newObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// 设置key和value的序列化规则
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(newStringRedisSerializer());

        redisTemplate.setHashKeySerializer(newStringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();return redisTemplate;}}

新建一个service实现发送验证码功能:

  1. 根据手机号查询是否已生成验证码,已生成直接返回
  2. 没有生成则生成6位验证码
  3. 调用短信服务发送短信
  4. 发送成功,将code保存至Redis,失效时间60s

代码实现如下:

/**
 * 发送验证码业务逻辑层
 * @author zjq
 */@ServicepublicclassSendVerifyCodeService{@ResourceprivateRedisTemplate<String,String> redisTemplate;/**
     * 发送验证码
     *
     * @param phone
     */publicvoidsend(String phone){// 检查非空AssertUtil.isNotEmpty(phone,"手机号不能为空");// 根据手机号查询是否已生成验证码,已生成直接返回if(!checkCodeIsExpired(phone)){return;}// 生成 6 位验证码String code =RandomUtil.randomNumbers(6);// 调用短信服务发送短信// 发送成功,将 code 保存至 Redis,失效时间 60sString key =RedisKeyConstant.verify_code.getKey()+ phone;
        redisTemplate.opsForValue().set(key, code,60,TimeUnit.SECONDS);}/**
     * 根据手机号查询是否已生成验证码
     *
     * @param phone
     * @return
     */privatebooleancheckCodeIsExpired(String phone){String key =RedisKeyConstant.verify_code.getKey()+ phone;String code = redisTemplate.opsForValue().get(key);returnStrUtil.isBlank(code)?true:false;}/**
     * 根据手机号获取验证码
     *
     * @param phone
     * @return
     */publicStringgetCodeByPhone(String phone){String key =RedisKeyConstant.verify_code.getKey()+ phone;return redisTemplate.opsForValue().get(key);}}

使用到的枚举类

RedisKeyConstant

@GetterpublicenumRedisKeyConstant{verify_code("verify_code:","验证码");privateString key;privateString desc;RedisKeyConstant(String key,String desc){this.key = key;this.desc = desc;}}

发送验证码的控制层代码如下:

/**
 * 发送验证码控制层
 * @author zjq
 */@RestControllerpublicclassSendVerifyCodeController{@ResourceprivateSendVerifyCodeService sendVerifyCodeService;@ResourceprivateHttpServletRequest request;/**
     * 发送验证码
     *
     * @param phone
     * @return
     */@GetMapping("send")publicResultInfosend(String phone){
        sendVerifyCodeService.send(phone);returnResultInfoUtil.buildSuccess("发送成功", request.getServletPath());}}

发送验证码接口,需要配置网关放放行发送验证码接口

/users/send

,配置如下:

secure:ignore:urls:# 配置白名单路径- /actuator/**- /auth/oauth/**- /users/signin
      - /users/send

验证发送:
在这里插入图片描述
在Redis中也可以查看到该手机号发送的验证码信息:
在这里插入图片描述
接下来继续走用户注册流程…

用户注册

校验手机号是否已注册或者不是可用状态

在mapper中新建一个通过手机号查询用户的方法:

/**
     * 根据手机号查询用户信息
     * @param phone
     * @return
     */@Select("select id, username, phone, email, is_valid "+" from t_users where phone = #{phone}")UsersselectByPhone(@Param("phone")String phone);

在service中创建校验手机号相关方法:

/**
     * 校验手机号是否已注册
     */publicvoidcheckPhoneIsRegistered(String phone){AssertUtil.isNotEmpty(phone,"手机号不能为空");Users diners = usersMapper.selectByPhone(phone);AssertUtil.isTrue(diners ==null,"该手机号未注册");AssertUtil.isTrue(diners.getIsValid()==0,"该用户已锁定,请先解锁");}

控制层创建相关接口,提供验证:

/**
     * 校验手机号是否已注册
     *
     * @param phone
     * @return
     */@GetMapping("checkPhone")publicResultInfocheckPhone(String phone){
        userService.checkPhoneIsRegistered(phone);returnResultInfoUtil.buildSuccess(request.getServletPath());}

网关同样需要配置放行该接口:

secure:ignore:urls:# 配置白名单路径- /actuator/**- /auth/oauth/**- /users/signin
      - /users/send
      - /users/checkPhone

此时数据库信息如下:
在这里插入图片描述

测试验证:
已存在的手机号:
image.png
不存在的手机号:
image.png
image.png
这个异常显然不够友好,接下来我们定义全局异常配置。

全局异常配置

添加全局异常处理类,代码如下:

/**
 * 全局异常处理类
 * @author zjq
 */@RestControllerAdvice@Slf4jpublicclassGlobalExceptionHandler{@ResourceprivateHttpServletRequest request;@ExceptionHandler(ParameterException.class)publicResultInfo<Map<String,String>>handlerParameterException(ParameterException ex){String path = request.getRequestURI();ResultInfo<Map<String,String>> resultInfo =ResultInfoUtil.buildError(ex.getErrorCode(), ex.getMessage(), path);return resultInfo;}@ExceptionHandler(Exception.class)publicResultInfo<Map<String,String>>handlerException(Exception ex){
        log.info("未知异常:{}", ex);String path = request.getRequestURI();ResultInfo<Map<String,String>> resultInfo =ResultInfoUtil.buildError(path);return resultInfo;}}

再次请求不存在的手机号,或者已经被锁定的手机号,返回如下:
在这里插入图片描述

image.png

查看用户名是否已经注册

在mapper中添加根据用户名查询用户:

/**
     * 根据用户名查询用户信息
     * @param username
     * @return
     */@Select("select id, username, phone, email, is_valid "+" from t_users where username = #{username}")UsersselectByUsername(@Param("username")String username);

用户注册验证都通过后需要把新用户添加到数据库,mapper中添加用户新增信息:

/**
     * 新增用户信息
     * @param userDTO
     * @return
     */@Insert("insert into "+" t_users (username, password, phone, roles, is_valid, create_date, update_date) "+" values (#{username}, #{password}, #{phone}, \"ROLE_USER\", 1, now(), now())")intsaveUser(UserDTO userDTO);

UserDTO内容如下:

packagecom.imooc.commons.model.dto;importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Getter;importlombok.Setter;importjava.io.Serializable;@Getter@Setter@ApiModel(description ="注册用户信息")publicclassDinersDTOimplementsSerializable{@ApiModelProperty("用户名")privateString username;@ApiModelProperty("密码")privateString password;@ApiModelProperty("手机号")privateString phone;@ApiModelProperty("验证码")privateString verifyCode;}

用户注册逻辑实现

用户注册步骤如下:

  1. 参数非空校验
  2. 验证码一致性校验
  3. 验证用户名是否已注册
  4. 注册
  5. 密码加密
  6. 自动登录

代码实现如下:

/**
     * 用户注册
     *
     * @param userDTO
     * @param path
     * @return
     */publicResultInforegister(UserDTO userDTO,String path){// 参数非空校验String username = userDTO.getUsername();AssertUtil.isNotEmpty(username,"请输入用户名");String password = userDTO.getPassword();AssertUtil.isNotEmpty(password,"请输入密码");String phone = userDTO.getPhone();AssertUtil.isNotEmpty(phone,"请输入手机号");String verifyCode = userDTO.getVerifyCode();AssertUtil.isNotEmpty(verifyCode,"请输入验证码");// 获取验证码String code = sendVerifyCodeService.getCodeByPhone(phone);// 验证是否过期AssertUtil.isNotEmpty(code,"验证码已过期,请重新发送");// 验证码一致性校验AssertUtil.isTrue(!userDTO.getVerifyCode().equals(code),"验证码不一致,请重新输入");// 验证用户名是否已注册Users users = usersMapper.selectByUsername(username.trim());AssertUtil.isTrue(users !=null,"用户名已存在,请重新输入");// 注册// 密码加密
        userDTO.setPassword(DigestUtil.md5Hex(password.trim()));
        usersMapper.saveUser(userDTO);// 自动登录returnsignIn(username.trim(), password.trim(), path);}

控制层代码如下:

/**
     * 注册
     *
     * @param userDTO
     * @return
     */@PostMapping("register")publicResultInforegister(@RequestBodyUserDTO userDTO){return userService.register(userDTO, request.getServletPath());}

验证

新用户发起注册。
校验手机号是否已注册:
image.png
发送验证码:
在这里插入图片描述
执行注册操作:
可以看到验证码为 807596:
image.png
第一次故意等待验证码失效再执行,返回如下:
在这里插入图片描述
然后重新发送验证码:
image.png
再次输入错误验证码,返回如下:
image.png
输入正确的,返回了自动登录的token信息:
在这里插入图片描述

本文内容到此结束了,
如有收获欢迎点赞👍收藏💖关注✔️,您的鼓励是我最大的动力。
如有错误❌疑问💬欢迎各位指出。
主页:共饮一杯无的博客汇总👨‍💻

保持热爱,奔赴下一场山海。🏃🏃🏃


本文转载自: https://blog.csdn.net/qq_35427589/article/details/127841874
版权归原作者 共饮一杯无 所有, 如有侵权,请联系我们删除。

“用户微服务用户注册功能实现”的评论:

还没有评论