controller
@PostMapping("/login") public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){ //实现登录功能 return userService.login(loginForm,session); }一、@RequestBody LoginFormDTO loginForm
@Data public class LoginFormDTO { private String phone; private String code; private String password; }1、前端传过来的是JSON格式
前端登录时,会传递:
{ "phone": "13800138000", "code": "123456", "password": "" }@RequestBody作用:接收JSON参数,并自动封装成 Java 对象。(没有这个注解,Spring 无法解析 JSON。)
2、DTO = Data Transfer Object(数据传输对象)
作用:
封装前端传来的所有登录参数(phone、code、password)
不用写多个参数,一个对象接收,更整洁、直接传
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 取出之前存入的数据
ServiceImpl
@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")注解
@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