01.Redis实现发送验证码保存功能

学习目标:

提示:学习如何利用Redis来实现发送验证码功能


学习产出:

1. 准备pom环境

java 复制代码
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.17</version>
        </dependency>

2. 配置ThreadLocal和过滤器

java 复制代码
public class UserHolder {
    private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();

    public static void saveUser(UserDTO user){
        tl.set(user);
    }

    public static UserDTO getUser(){
        return tl.get();
    }

    public static void removeUser(){
        tl.remove();
    }
}
java 复制代码
@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Autowired
    private StringRedisTemplate redis;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(
        new LoginInterceptor(redis))
        //哪些请求放行不走过滤器
     .excludePathPatterns("/user/code","/user/login","/blog/hot","/shop/**","/shop-type/**","/voucher/**");
    }
}
---------------------------------------------
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    private StringRedisTemplate redis;

    public LoginInterceptor(StringRedisTemplate redis) {
        this.redis = redis;
    }

    //controller执行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.获取请求头中的token
        String authorization = request.getHeader("authorization");
        if (StrUtil.isBlank(authorization)) {
            response.setStatus(401);
            return false;
        }
        //2.基于token获取Redis中的用户
        Map<Object, Object> userMap = redis.opsForHash().entries("login:token:" + authorization);
        //3.判断用户是否存在
        if (userMap.isEmpty()) {
            //4.不存在,拦截,401
            response.setStatus(401);
            return false;
        }
        //5.将查询到的Hash数据转换为Dto对象
        UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
        //6.存在,保存信息到ThreadLocal
        UserHolder.saveUser(userDTO);
        //7.访问接口每次都会刷新token过期时间
        redis.expire("login:token:" + authorization,30,TimeUnit.MINUTES);
        //7.放行
        return true;
    }
    //渲染后返回给前台数据前
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //移除用户,避免内存泄露
        UserHolder.removeUser();
    }
}

3. Controller层:负责接收请求和向下分配

java 复制代码
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    /**
     * 发送手机验证码
     */
    @PostMapping("code")
    public Result sendCode(@RequestParam("phone") String phone) {
        //调用Service层来实现具体逻辑
        return userService.sendCode(phone);
    }


}

4. Service层:负责业务的处理逻辑

java 复制代码
package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hmdp.dto.LoginFormDTO;
import com.hmdp.dto.Result;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.User;
import com.hmdp.mapper.UserMapper;
import com.hmdp.service.IUserService;
import com.hmdp.utils.RegexUtils;
import com.hmdp.utils.SystemConstants;
import com.hmdp.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.xml.validation.Validator;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.hmdp.utils.RedisConstants.*;
import static com.hmdp.utils.SystemConstants.USER_NICK_NAME_PREFIX;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    private static final ObjectMapper mapper = new ObjectMapper();
    @Resource
    private StringRedisTemplate redis;

    @Override
    public Result sendCode(String phone) {
        //1.校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2.如果不符合,返回错误信息
            return Result.fail("无效手机号");
        }
        //3.符合,生成验证码
        String code = RandomUtil.randomNumbers(6);
        //4.保存验证码到Redis中
        redis.opsForValue().set(USER_NICK_NAME_PREFIX + phone, code, 60, TimeUnit.SECONDS);
        //5.模拟发送验证码
        log.info("发送验证码为===> {}", code);
        //6.返回
        return Result.ok();
    }


    //通过手机号创建新用户
    private User createUserWithPhone(String phone) {
        //创建用户
        User user = new User();
        user.setPhone(phone);
        user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));
        save(user);
        return user;
    }
}
相关推荐
qq_246839757 分钟前
Redis lua 执行性能优化
redis·性能优化·lua
倔强的石头_8 分钟前
MySQL 兼容性深度解析:从内核级优化到“零修改”迁移工程实践
前端·数据库
偏执网友13 分钟前
项目Redis报错解决
redis
水杉i15 分钟前
Redis 使用笔记
数据库·redis·笔记
学不完的15 分钟前
redis
数据库·redis·缓存·运维开发
木与长清20 分钟前
人鼠同源基因离线转换
数据库·矩阵·数据分析·r语言
Hello.Reader21 分钟前
Flutter IM 桌面端消息发送、ACK 回执、SQLite 本地缓存与断线重连设计
flutter·缓存·sqlite
wanhengidc24 分钟前
服务器 数据安全稳定
运维·服务器·数据库·游戏·智能手机
tingting011924 分钟前
linux系统-统计连接数-钉钉告警
linux·数据库·钉钉
山峰哥25 分钟前
数据库工程中的SQL调优策略与实践:从索引优化到执行计划分析
数据库·sql·性能优化