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(数据传输对象)
作用:
- 封装前端传来的所有登录参数(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 取出之前存入的数据
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