用户注册接口思路分析

本文详细描述了Java应用中控制器层如何调用服务层接口,涉及用户注册过程中的参数处理、密码加密、头像存储、账号唯一性检查,以及验证码和邮箱验证的实现策略,包括Redis缓存的使用。
摘要由CSDN通过智能技术生成

目录

🦽1.controller层接口

🦼2.service层接口实现

 🛹3.验证码的实现类


1.controller层接口

controller传递前端返回的参数合调用service层接口,方便管理

  @ApiOperation("用户注册")
    @PostMapping("/register")
    public JsonData register(@ApiParam(value = "用户注册对象")
                             @RequestBody UserRegister userRegister) {
        JsonData register = userService.register(userRegister);
        return JsonData.buildSuccess(register);
    }

2.service层接口实现

service对注册用户进行处理:

  • 1.密码加密:如果使用简单的MD5或其他加密方式很容易,例如(cmd5.com解密网站),当在MD5后在拼接上盐,则可以加大破解难度
  • 2.头像:有专门的oss对象存储接口,返回图片地址然后在存储到数据库中
  • 3.账号唯一性:在大高并发下,很难保证账号的唯一性,我们直接在数据库中使用唯一索引
@Slf4j
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private NotifyService notifyService;

    @Override
    public UserDO getById(Long id) {
        return userMapper.selectById(id);
    }

    /**
     * 用户注册
     *
     * @param userRegister
     * @return
     */
    @Override
    public JsonData register(UserRegister userRegister) {

        Boolean checkCode = false;
        //判断邮箱是否合规
        if (StringUtils.isNotBlank(userRegister.getMail())) {
            //调用接口,校验验证码
            checkCode = notifyService.checkCode(SendCodeEnum.USER_REGISTER, userRegister.getMail(), userRegister.getCode());
        }

        //验证错误,直接返回
        if (!checkCode) {
            return JsonData.buildResult(CodeEnum.CODE_ERROR);
        }
        //创建UserDo数据模型
        UserDO userDO = new UserDO();
        //将UserRegister的属性拷贝到数据模型userDO中
        BeanUtils.copyProperties(userRegister, userDO);
        //设置创建日期
        userDO.setCreateTime(new Date());
        //设置个性签名
        userDO.setSlogan(userRegister.getSlogan());
        //设置头像
        userDO.setHeadImg(userRegister.getHeadImage());
        userDO.setSex(userRegister.getSex());
        //TODO 设置密码,md5加密
        //生成密钥盐
        userDO.setSecret("$1$" + CommonUtil.getStringNumRandom(8));
        //密码+盐处理
        String password = Md5Crypt.md5Crypt(userRegister.getPwd().getBytes(), userDO.getSecret());
        userDO.setPwd(password);
        //TODO 账号唯一性检查
        if (checkUnique(userDO.getMail())) {
            int rows = userMapper.insert(userDO);
            log.info("rows:{},注册成功:{}", rows, userDO.toString());
            //TODO 初始化信息,发放福利
            //保存到数据库
            userRegisterInitTask(userDO);
            return JsonData.buildSuccess();
        } else {
            return JsonData.buildResult(CodeEnum.ACCOUNT_REPEAT);
        }

    }

    /**
     * 校验账号是否唯一
     *
     * @param mail
     * @return
     */
    private boolean checkUnique(String mail) {
        List<UserDO> mailCheck = userMapper.selectList(new QueryWrapper<UserDO>().eq("mail", mail));
        return mailCheck.size() > 0 ? false : true;
    }

}

疑惑解答:

对于为什么不直接使用UserDo传参,而是重新建个含部分UserDo属性的对象?

  • 我也很疑惑,后来请教了一下大佬,他说:dao层不用打包出去,避免数据库暴露,api模块和orm操作模块衍生出的,单体项目没必要!!!
  • 豁然开朗后,我的理解:以后dao只作为与数据库连接的桥梁,而每当用到部分属性作为参数时,重新构建实体类,然后在将构建好的实体类,利用(BeanUtils.copyProperties)拷贝到dao层上,在设置相关属性

 3.验证码的实现类

发送验证码思路分析:

  • 1.指定key的名称
  • 2.根据key获取value(验证码)
  • 3.将随机数拼接上时间戳(方便校验时间),存入缓存中并设置过期时间
  • 4.判断邮箱是否合规
  • 5.调用邮箱发送接口,将验证码发送给邮箱
  • 6.60秒内不能重复发送
    • 获取的value如果不为空,通过分割字符换获取时间戳
    • 当前时间-分割字符串获取的时间<60秒,直接返回不能重复发送

校验验证码思路分析:

  • 1.根据指定规则获取key
  • 2.根据key获取value(验证码)
  • 3. 判断获取的value(验证码)是否为空
  • 4.根据获取的value利用字符串分割,取出时间戳,获取真正的验证码
  • 5.判断获取的真正验证码是否与用户传递过来的验证码相等
    • 相等,返回true
    • 否则,返回false
@Slf4j
@Service
public class NotifyServiceImpl implements NotifyService {


    @Autowired
    private MailService mailService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String SUBJECT = "欢迎查收小张的邮箱~";
    private static final String CONTENT = "你的验证码%s,有效时间60秒,悄悄地哦";

    //过期时间10分钟
    private static final int CODE_EXPIRED = 60 * 1000 * 10;

    /**
     * 发送验证码
     *
     * @param sendCodeEnum:发送类型
     * @param to:收件人邮箱
     * @return
     */
    @Override
    public JsonData sendCode(SendCodeEnum sendCodeEnum, String to) {

        //获取缓存key
        String cacheKey = String.format(CaptchaKey.CAPTCHA_CODE_KEY, sendCodeEnum.name(), to);
        //根据key获取value
        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
        //如果不为空,则判断60秒内重复发送
        if (StringUtils.isNotBlank(cacheValue)) {
            long ttl = Long.parseLong(cacheValue.split("_")[1]);
            //当前时间戳-验证码发送时间错,如果小于60,不重复发送
            if (CommonUtil.getCurrentTimestamp() - ttl < 1000 * 60) {
                log.info("重复发送验证码,时间间隔:{}秒", (CommonUtil.getCurrentTimestamp() - ttl) / 1000);
                return JsonData.buildResult(CodeEnum.CODE_LIMITED);
            }
        }

        //获取随机验证码
        String randomCode = CommonUtil.getRandomCode(6);
        //获取到的验证码拼接上时间戳
        String value = randomCode + "_" + CommonUtil.getCurrentTimestamp();
        //将拼接后的验证码存到redis中
        redisTemplate.opsForValue().set(cacheKey, value, CODE_EXPIRED, TimeUnit.MILLISECONDS);
        //1.判断是否合规
        if (CheckUtil.isEmail(to)) {
            //指定邮箱验证的位数
            //发送随机验证码
            mailService.sendMail(to, SUBJECT, String.format(CONTENT, randomCode));
            log.info("验证码发送成功:{}",randomCode);
            return JsonData.buildSuccess("发送随机验证成功~");
        } else {
            return JsonData.buildResult(CodeEnum.CODE_TO_ERROR);
        }
    }

    /**
     * 校验验证码
     *
     * @param sendCodeEnum:类型
     * @param to:接受验证码的人
     * @param code:验证码
     * @return
     */
    @Override
    public boolean checkCode(SendCodeEnum sendCodeEnum, String to, String code) {
        //获取key
        String cacheKey = String.format(CaptchaKey.CAPTCHA_CODE_KEY, sendCodeEnum.name(), to);
        //根据key获取验证码
        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
        //判断验证码是否为空
        if (StringUtils.isNotBlank(cacheValue)) {
            //因为存储的时候是3123_312351521的形式,所以进行切割,获取真正的验证码
            String cacheCode = cacheValue.split("_")[0];
            //校验验证码是否相等
            if (cacheCode.equals(code)) {
                //相等的话,删除key,防止重复
                redisTemplate.delete(cacheKey);
                return true;
            }

        }
        return false;
    }
}
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
创建一个Python书店项目,可以是一个基于Web的应用程序,用来管理书籍信息、库存和销售。以下是构建这样一个项目的大概思路: 1. **需求分析**: - 用户管理:支持注册、登录、个人信息管理等。 - 书籍管理:包括添加、编辑、删除书籍信息(如书名、作者、分类、价格等)。 - 库存管理:实时跟踪每本书的库存数量。 - 购物车功能:用户可以选择心仪书籍并加入购物车。 - 结算流程:计算总价,支持在线支付。 2. **技术选型**: - 前端:使用HTML/CSS/JavaScript以及React或Vue等框架构建用户界面。 - 后端:Python搭配Django或Flask框架,处理数据逻辑。 - 数据库:SQLite、MySQL或PostgreSQL存储书籍信息和用户数据。 - 安全性:使用HTTPS、JWT或OAuth进行身份验证和授权。 3. **模块设计**: - 用户模块:负责用户账户、权限控制和认证。 - 书籍模块:管理书籍数据和库存操作。 - 购物车模块:处理购物车功能,如添加、删除商品。 - 订单模块:处理订单生成、支付接口集成。 4. **开发过程**: - 设计数据库模型:创建必要的表和关系。 - 实现后端API:根据需求定义RESTful API接口。 - 编前端代码:交互式地展示数据和处理用户输入。 5. **测试与部署**: - 单元测试:确保每个功能模块的正确性。 - 集成测试:检查各个模块之间的协作。 - 部署到服务器:使用Heroku、AWS或其他云服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会敲代码的小张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值