【Redis实战】击穿+雪崩+穿透

架构

image.png

短信登录

基于session实现登录

流程图

image.png

代码实现
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
   
   

    /**
     * session用户key
     */
    public static final String USER_CONSTANT = "user";

    @Override
    public Result sendCode(String phone, HttpSession session) {
   
   
        //校验手机号码
        boolean phoneInvalid = RegexUtils.isPhoneInvalid(phone);
        if (phoneInvalid) {
   
   
            return Result.fail("手机号码格式错误!");
        }
        //生成6位数的验证码
        String code = RandomUtil.randomNumbers(6);
        session.setAttribute("code", code);
        //发送验证码
        log.info("send code success,code={}", code);
        return Result.ok();
    }

    @Override
    public Result login(LoginFormDTO loginForm, HttpSession session) {
   
   
        //校验手机号码
        if (Objects.isNull(loginForm)) {
   
   
            return Result.fail("参数为空!");
        }
        String phone = loginForm.getPhone();
        if (RegexUtils.isPhoneInvalid(phone)) {
   
   
            return Result.fail("手机号码格式错误!");
        }
        //验证码校验
        String code = (String) session.getAttribute("code");
        if (StringUtils.isBlank(code) || !StringUtils.equals(code, loginForm.getCode())) {
   
   
            return Result.fail("验证码错误!");
        }
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getPhone, phone);
        User user = getOne(wrapper);
        if (!Objects.nonNull(user)) {
   
   
            //注册新用户
            user = getNewUserByPhone(phone);
            save(user);
        }
        session.setAttribute(USER_CONSTANT, BeanUtil.copyProperties(user, UserDTO.class));
        return Result.ok();
    }

    /**
     * 根据手机号码创建新用户
     *
     * @param phone 手机号码
     * @return
     */
    private User getNewUserByPhone(String phone) {
   
   
        User user = new User();
        user.setCreateTime(LocalDateTime.now());
        user.setPhone(phone);
        user.setNickName(SystemConstants.USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));
        user.setUpdateTime(LocalDateTime.now());
        return user;
    }
}
集群session共享问题

image.png

session数据拷贝可以解决这个问题,但是多台tomcat之间存储相同的数据会浪费内存空间,拷贝会有数据延迟。
session每个浏览器有不同的code,tomcat里保存里很多code。

基于Redis实现session登录

验证码流程图

image.png

代码实现
    public Result sendCode(String phone, HttpSession session) {
   
   
        //校验手机号码
        boolean phoneInvalid = RegexUtils.isPhoneInvalid(phone);
        if (phoneInvalid) {
   
   
            return Result.fail("手机号码格式错误!");
        }
        //生成6位数的验证码
        String code = RandomUtil.randomNumbers(6);
        //保存验证码到redis
        stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.SECONDS);
        //发送验证码
        log.info("send code success,code={}", code);
        return Result.ok();
    }
校验流程图

image.png

代码实现

登录

    public Result login(LoginFormDTO loginForm, HttpSession session) {
   
   
        //校验手机号码
        if (Objects.isNull(loginForm)) {
   
   
            return Result.fail("参数为空!");
        }
        String phone = loginForm.getPhone();
        if (RegexUtils.isPhoneInvalid(phone)) {
   
   
            return Result.fail("手机号码格式错误!");
        }
        //验证码校验
        String code = (String) session.getAttribute("code");
        if (StringUtils.isBlank(code) || !StringUtils.equals(code, loginForm.getCode())) {
   
   
            return Result.fail("验证码错误!");
        }
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getPhone, phone);
        User user = getOne(wrapper);
        if (!Objects.nonNull(user)) {
   
   
            //注册新用户
            user = getNewUserByPhone(phone);
            save(user);
        }
        session.setAttribute(USER_CONSTANT, BeanUtil.copyProperties(user, UserDTO.class));
        return Result.ok();
}

登录拦截器

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpStatus;
import com.hmdp.dto.UserDTO;
import com.hmdp.utils.UserHolder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值