开发中简易的用户注册验证 £神魔★判官ぃ 2022-11-26 04:56 165阅读 0赞 ## 开发中简易的用户注册验证 ## ##### 登录页面 ##### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzU1NTM4MA_size_16_color_FFFFFF_t_70] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzU1NTM4MA_size_16_color_FFFFFF_t_70 1] 拆分需求 1:校验手机号码是否正确 2:校验手机号是否已经注册 3:校验注册信息格式是否正确(非空校验,等值校验,长度等) 4:发送注册短信验证码 5:用户注册 ##### UserController(控制器层) ##### @RestController @RequestMapping("/users") public class UserController { @GetMapping("/checkPhone") //1.验证手机号是否存在 public Object checkPhone(String phone) boolean ret = userInfoService.checkPhone(phone); return !ret; } //2.生成验证码并缓存daoredis数据库中 @GetMapping("/sendVerifyCode") public Object sendVerifyCode(String phone) { userInfoService.sendVerifyCode(phone); return JsonResult.success(); } //3.注册验证,验证手机号,密码,验证码等 @PostMapping("/regist") public Object regist(String phone, String nickname, String password, String rpassword, String verifyCode) { userInfoService.regist(phone, nickname, password, rpassword, verifyCode); return JsonResult.success(); } } ##### UserInfoServiceImpl(service层) ##### @Service public class UserInfoServiceImpl implements IUserInfoService { //1.验证手机号是否存在 public boolean checkPhone(String phone) { UserInfo userInfo = userInfoRepository.findByPhone(phone); return userInfo != null; } //2.生成验证码并缓存daoredis数据库中 public void sendVerifyCode(String phone) { //生成验证码 String code = UUID.randomUUID() .toString().replaceAll("-", "") .substring(0, 4); StringBuilder sb = new StringBuilder(); sb.append("您的验证码为:").append(code) .append(",请在") .append(Consts.VERIFY_CODE_VAI_TIME) .append("分钟内填写完成!").append("退订回T"); System.out.println(sb); //真实发送短信:本质就是使用java发起http请求 //Springmvc提供一个工具类:RestTemplate 用于发起http请求 RestTemplate template = new RestTemplate(); //短信接口url //Url:https://way.jd.com/jixintong/hyapi?tos=13580305095&msg=【中正云通信】您的JD验证码为:6266,欢迎注册使用。&appkey=26390e995be3c936e7c35cca09742ae0 String url = "https://way.jd.com/jixintong/hyapi?tos={1}&msg=【中正云通信】{2}&appkey={3}"; String ret = template.getForObject(url, String.class, phone, sb.toString(), "26390e995be3c936e7c35cca09742ae0"); System.out.println(ret); if (!ret.contains("Success")) { throw new LogicException("短信发送失败"); } //缓存到redis数据库中 userInfoRedisService.setVerifyCode(phone, code); } //3.用户注册验证 @Override public void regist(String phone, String nickname, String password, String rpassword, String verifyCode) { //一般用户验证都需要后端验证,因为前端验证不保险 //1.验证参数不能为空 /* if(StringUtils.hasLength(phone)){ throw new RuntimeException("电话号码不能为空"); } 这样写没有问题,但是参数判空太多了,一直这样重复代码不优雅,我们需要将它抽取出来 */ //Assert.hasText(phone, "电话号码不能为空"); 参数断言工具类,这样也可以,但是它的异常类型写死了,我们需要自己写一个自定义异常 AssertUtil.hasText(phone, "电话号码不能为空"); AssertUtil.hasText(nickname, "昵称不能为空"); AssertUtil.hasText(password, "密码不能为空"); AssertUtil.hasText(rpassword, "确认密码不能为空"); AssertUtil.hasText(verifyCode, "验证码不能为空"); //2.2次密码是否一致 AssertUtil.isEquals(password, rpassword, "密码不正确"); //3.电话号码格式是否正确 String regex = "^1[3-9]\\d{9}$"; if (!phone.matches(regex)) { throw new LogicException("电话号码格式错误"); } //4.电话号码是否正确 if (this.checkPhone(phone)) { throw new LogicException("电话号码已经存在"); } //5.验证码是否与缓存的一致 //1.获取缓存的密码 String code = userInfoRedisService.getVerifyCode(phone); if (!verifyCode.equals(code)) { throw new LogicException("验证码错误"); } //注册 //将值设置到UserInfo对象中 UserInfo userInfo = new UserInfo(); userInfo.setNickname(nickname); userInfo.setPhone(phone); userInfo.setPassword(password); userInfo.setHeadImgUrl("/images/default.jpg"); this.save(userInfo); } } ##### UserInfoRepository(Repository层类似于操作sql语句时的Mapper接口) ##### @Repository public interface UserInfoRepository extends MongoRepository<UserInfo, String> { /** * 查询用户 * @param phone * @return */ UserInfo findByPhone(String phone); } ##### UserInfoRedisServiceImpl(用于缓存验证码以及登录信息) ##### @Service public class UserInfoRedisServiceImpl implements IUserInfoRedisService { @Autowired private StringRedisTemplate template; //将验证码缓存到redis中 @Override public void setVerifyCode(String phone, String code) { //key设计使用枚举类 String key = RedisKeys.VERIFY_CODE.join(phone); //缓存并设置有效时间 template.opsForValue().set(key, code, VERIFY_CODE.getTime(), TimeUnit.SECONDS); } //获取redis缓存中的验证码 @Override public String getVerifyCode(String phone) { String key = RedisKeys.VERIFY_CODE.join(phone); return template.opsForValue().get(key); } } ##### 参数断言判断工具类 ##### public abstract class AssertUtil { //参数非空判断 public static void hasText(String text, String message) { if (!StringUtils.hasText(text)) { throw new LogicException(message); } } //密码验证 public static void isEquals(String password, String rpassword, String msg) { //注意,先判断密码是否为空,严谨 if (password == null || rpassword == null) { throw new LogicException("密码不能为空"); } //再判断密码是否相同 if (!password.equals(rpassword)) { throw new LogicException(msg); } } } #### 自定义异常 #### public class LogicException extends RuntimeException { public LogicException(String message) { super(message); } } #### redis中key键设计善于枚举类 #### //redis key重设计,因为在业务层设计key键会导致有可能和其他人设计名字重复, //所有我们可以将key键统一放在枚举类中管理,这样key就不会重复了 @Getter public enum RedisKeys { VERIFY_CODE("verify_code", Consts.VERIFY_CODE_VAI_TIME * 60L), USER_LOGIN_TOKEN("user_login_token", Consts.USER_INFO_TOKEN_VAI_TIME * 60L); //相当于下面写法 //public static final RedisKeys VERIFY_CODE // =new RedisKeys("verify_code", Consts.VERIFY_CODE_VAI_TIME * 60L); private String prefix; private Long time; private RedisKeys(String prefix, Long time) { this.prefix = prefix; this.time = time; } //用于拼接key public String join(String... values) { StringBuilder sb = new StringBuilder(); sb.append(prefix); for (String value : values) { sb.append(":").append(value); } return sb.toString(); } } #### 统一异常处理类 #### //统一异常处理类 @ControllerAdvice public class CommonExceptionHandler { // 逻辑异常处理,自己定义的异常类型,只要发生异常都会来到这里处理,并返回相应的json信息 @ResponseBody @ExceptionHandler(LogicException.class) public Object LogicExp(Exception e, HttpServletResponse resp) { e.printStackTrace(); resp.setContentType("application/json;charset=utf-8"); return JsonResult.error(JsonResult.CODE_ERROR_PARAM, e.getMessage(), null); } // 系统其它异常,就返回固定的系统繁忙等,不要将系统自身的bug返回给客户了 @ResponseBody @ExceptionHandler(RuntimeException.class) public Object runtimeExp(Exception e, HttpServletResponse resp) { e.printStackTrace(); resp.setContentType("application/json;charset=utf-8"); return JsonResult.defaultError(); } } [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzU1NTM4MA_size_16_color_FFFFFF_t_70]: /images/20221124/c86bf4aaef7c42198e7ce6d4432a1c47.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzU1NTM4MA_size_16_color_FFFFFF_t_70 1]: /images/20221124/82255efd381f44558330dc47e3a8440f.png
还没有评论,来说两句吧...