Redis入门到精通【实战篇】【一】

本系列作品持续更新中~
Redis入门到精通【基础篇】【一】
Redis入门到精通【基础篇】【二】
Redis入门到精通【基础篇】【三】
Redis入门到精通【实战篇】【一】


前言

经过基础篇的学习,相信读者们以及对Redis有了一定的了解,那么接下来我们就开始Redis实战篇的训练,帮助大家进一步学习和掌握Redis

项目前置资料

实战篇教程引用自黑马程序员Redis入门到实战教程,在此感谢老师的辛苦教学。此外笔者对教程内容进行优化和精简,还请读者们放心食用

项目前置资料

基于Session的短信登录

基于Session的短信登录有三大步骤:
1.发送短信验证码
2.短信验证码登录和注册
3.校验登录状态

以下是短信登录模块的流程图:
在这里插入图片描述

发送短信验证码

Service层的实现

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

    @Override
    public Result sendCode(String phone, HttpSession session) {
        // 1.校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            // 2.如果不符合,返回错误信息
            return Result.fail("手机号格式错误!");
        }

        // 3.符合,生成验证码
        String code = RandomUtil.randomNumbers(6);

        // 4.保存验证码到session
        session.setAttribute("code", code);

        // 5.发送验证码,本篇的旨`Redis的应用,发送验证码需外接API操作等,不是本篇重心,因此此处采用日志的伪代码实现
        log.debug("发送验证码成功,验证码为:" + code);

        // 返回ok
        return Result.ok();
    }
}

Controller层的实现

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private IUserService userService;

    @Resource
    private IUserInfoService userInfoService;

    /**
     * 发送手机验证码
     */
    @PostMapping("code")
    public Result sendCode(@RequestParam("phone") String phone, HttpSession session) {
        // TODO 发送短信验证码并保存验证码
        return userService.sendCode(phone, session);
    }
}

短信注册和登录

Service层的实现

UserService实现以下代码:

@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
    // 1.校验手机号
    String phone = loginForm.getPhone();
    if (RegexUtils.isPhoneInvalid(phone)) {
        // 2.如果不符合,返回错误信息
        return Result.fail("手机号格式错误!");
    }

    // 2.校验验证码
    Object cacheCode = session.getAttribute("code");
    String code = loginForm.getCode();
    if (cacheCode == null || !cacheCode.toString().equals(code)) {
        // 3.不一致,报错
        return Result.fail("验证码错误!");
    }

    // 4.一致,根据手机号查询用户
    User user = query().eq("phone", phone).one();

    // 5.判断用户是否存在
    if (user == null){
        // 6.不存在,创建新用户并保存
        user = createUserWithPhone(phone);
    }

    // 7.保存用户信息到session中
    session.setAttribute("user", user);

    return Result.ok();
}

private User createUserWithPhone(String phone) {
    // 创建用户
    User user = new User();
    user.setPhone(phone);
    user.setNickName(SystemConstants.USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));

    // 保存用户
    save(user);
    return user;
}

Controller层的实现

UserController实现以下代码:

@PostMapping("/login")
public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){
    // TODO 实现登录功能
    return userService.login(loginForm, session);
}

登录校验拦截器

设计登录拦截器

Util包中新建LoginInterceptor类,如下:

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.获取session
        HttpSession session = request.getSession();
        // 2.获取session中的用户
        Object user = session.getAttribute("user");
        // 3.判断用户是否存在
        if (user == null) {
            // 4.用户不存在,拦截
            response.setStatus(401);
            return false;
        }
        // 5.用户存在,保存用户信息到ThreadLocal
        UserHolder.saveUser((User) user);
        // 6.放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 移除用户
        UserHolder.removeUser();
    }
}

配置拦截器

config包下新建MvcConfig类来配置拦截器,如下:

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .excludePathPatterns(
                        "/user/code",
                        "/user/login",
                        "/blog/hot",
                        "/shop/**",
                        "/shop-type/**",
                        "/upload/**",
                        "/voucher/**"
                );

    }
}

Controller层的实现

UserController实现以下代码:

@GetMapping("/me")
public Result me(){
    // TODO 获取当前登录的用户并返回
    User user = UserHolder.getUser();
    return Result.ok(user);
}

隐藏用户敏感信息

新建UserDTO

我们新建UserDTO来保存User中部分信息

@Data
public class UserDTO {
    private Long id;
    private String nickName;
    private String icon;
}

修改UserHolder类

我们将UserHolder类中的User都改为UserDTO,这样在保存,获取和移除操作中只需使用部分User信息,即保护了用户隐私,又大大减轻了内存压力,如下:

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();
    }
}

在使用UserHolder的实例中也需修改UserUserDTO对象


本节结束

本系列作品持续更新中~

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-04-30 14:52:01       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-30 14:52:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-30 14:52:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-30 14:52:01       20 阅读

热门阅读

  1. 微信小程序 图片上传到文件服务器

    2024-04-30 14:52:01       12 阅读
  2. 吐槽某为的招聘是最恶心的招聘,没有之一

    2024-04-30 14:52:01       11 阅读
  3. 使用 Lua 协程模拟 Golang 的 go defer 编程模式

    2024-04-30 14:52:01       14 阅读
  4. React 模板选择标准

    2024-04-30 14:52:01       13 阅读
  5. git的使用

    2024-04-30 14:52:01       14 阅读
  6. 机遇与挑战并存的Agent

    2024-04-30 14:52:01       14 阅读
  7. 深度刨析JVM垃圾收集的艺术

    2024-04-30 14:52:01       12 阅读