redis_点评详解(02.短信登录-验证码登录注册)

1、controller

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

一、@RequestBody LoginFormDTO loginForm

typescript 复制代码
@Data
public class LoginFormDTO {
    private String phone;
    private String code;
    private String password;
}
1、前端传过来的是 JSON 格式

前端登录时,会传递:

json 复制代码
{
  "phone": "13800138000",
  "code": "123456",
  "password": ""
}

@RequestBody 作用:接收 JSON 参数,并自动封装成 Java 对象。(没有这个注解,Spring 无法解析 JSON。)

2、DTO = Data Transfer Object(数据传输对象)

作用:

  1. 封装前端传来的所有登录参数(phone、code、password)
  2. 不用写多个参数,一个对象接收,更整洁、直接传 loginForm 对象即可
3、为什么加@Date
  • 所属框架:Lombok 框架提供的注解
  • 自动生成方法:

getter / setter

toString

equals / hashCode

不用手写,简化代码、让 Spring 可以自动封装 JSON 数据

@Data在当前登录代码里的实际用处是配合 @RequestBody 自动封装 JSON,前端传 JSON 手机号、验证码,Spring 能自动把 JSON 映射到 LoginFormDTO 对象,必须要有 setter 才能注入赋值。

4、总结:前端传 JSON → @RequestBody 接收 → 自动封装进 LoginFormDTO 对象 → 方便后续业务使用。

二、HttpSession session

  • 所属包:javax.servlet.http.HttpSession(属于 Java Web Servlet 原生 内置对象)

  • 作用:服务端会话技术,用来保存当前浏览器用户的私有数据,记录登录状态、临时数据

  • 常用两个核心方法:

    • 1、存数据

      • session.setAttribute("key", 对象/数据);
      • key-value 键值对 把数据存在服务端当前用户会话中
    • 2、取数据

      • session.getAttribute("key");
      • 根据 key 取出之前存入的数据

      2、ServiceImpl

ini 复制代码
@Override
    public Result login(LoginFormDTO loginForm, HttpSession session) {
        //1.校验手机号
        String phone = loginForm.getPhone();
        if(RegexUtils.isPhoneInvalid(phone)){
            //2.如果不符合,返回错误信息
            return Result.fail("手机号格式错误");
        }
        //2.校验验证码
        String code = loginForm.getCode();
        Object cacheCode = session.getAttribute("code");
        if(cacheCode==null||!cacheCode.toString().equals(code)) {
            //3.不一致,报错
            return Result.fail("验证码错误");
        }

        //4.一致,根据手机号查询用户 select * from tb_user where phone = ?
        //eq 是「Equal」的缩写,意思是「等于」,对应 SQL 中的 WHERE phone = ?。
        //因为上述<UserMapper, User>中User方法中使用了@TableName("tb_user")指定实体类对应数据库表名的,否则需要加通过 from() 方法显式指定表名 tb_user:
        //User user = query().from("tb_user").eq("phone", phone).one();
        User user = query().eq("phone", phone).one();//这里查一个就是.one(),查多个就是list()

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

        //7.存在-保存用户信息到session中
        session.setAttribute("user",user);
        return Result.ok();
    }

    private User createUserWithPhone(String phone) {
        //1.创建用户
        User user=new User();
        user.setPhone(phone);
        //向user中插入一个随机的用户昵称
        user.setNickName("user_"+RandomUtil.randomString(10));
        /*setNickName 是 User 实体类中的Setter(设置器)方法,作用是给 User 对象的 nickName(昵称)字段赋值。
你看不到这个方法的手写代码,是因为 User 类上标注了 @Data 注解(Lombok 框架提供),Lombok 会在编译时自动生成这个方法,无需你手动编写。* /

        //2.保存用户到数据库(MyBatis-Plus 提供的方法)
        // save(user) 等价于执行 INSERT INTO tb_user (phone, nick_name, icon, ...) VALUES (?, ?, ?, ...)
        save(user);
        return user;
    }

三、为什么 session.getAttribute ("code") 返回类型是 Object

Object cacheCode = session.getAttribute("code");

根据上述我们知道取出来的是之前插入的数据,那为什么返回值类型却是Object呢?

session.getAttribute("key") 可以存任何类型的数据

但是HttpSession 是一个通用容器、设计上不限制存储的数据类型,程序运行时无法提前预知你存入的具体是什么类型。所以统一用 Object 接收(所有类的父类);然后接下来向下强制类型转换(强转);

四、MyBatis-Plus 链式查询:query().eq("phone", phone).one();

等价于 SQL:SELECT * FROM tb_user WHERE phone = ?

query() MP 提供的链式查询构造器,开启查询操作。

eq("字段名", 值) eq = Equal(等于),对应 SQL 的 WHERE 条件。

one() 表示查询 1 条结果并返回对象;若查询多条数据使用 list()

1、为什么代码中不使用 from () 声明表名?

  • 1、User 实体类上使用了 @TableName("tb_user") 注解
kotlin 复制代码
@TableName("tb_user")
public class User implements Serializable {
}

这个注解是 MyBatis-Plus 提供的,作用是:

告诉 MyBatis-Plus,当前 User 类对应数据库里的 tb_user 表。

  • 2、MyBatis-Plus 会自动识别表名

因为 UserServiceImpl 继承了 ServiceImpl<UserMapper, User>

  • 泛型中指定了操作的实体是 User
  • MP 自动读取 User 类上的 @TableName("tb_user")
  • 自动拼接成 from tb_user
相关推荐
Xidaoapi1 小时前
5分钟让你的Python项目接入GPT-4:从配置到上线的完整指南
后端
SamDeepThinking1 小时前
写代码不考虑前后兼容,迟早要还的
java·后端·程序员
庞轩px2 小时前
第四篇:SpringBoot自动配置——约定大于配置的底层原理
java·spring boot·后端·spring·自动配置·注解开发
追逐时光者2 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 70 期(2026年5.01-5.10)
后端·.net
程序员清风2 小时前
科普一下:大模型Token的收费逻辑!
java·后端·面试
Nyarlathotep01132 小时前
并发集合类(4):ArrayBlockingQueue
java·后端
石小石Orz3 小时前
Harness Engineering 到底是什么?概念、实战与争议,一次全部讲清楚
前端·后端
镜花水月linyi4 小时前
GitHub 已开源:民政部官方的国家地名信息库 MCP & Skill 实现
后端·ai编程·mcp
swipe4 小时前
别把 Agent 写成一团 Prompt:用 LangGraph 把多 Agent 系统变成可控状态机
后端·langchain·llm