公告

记录一下自己学习和生活中的所见所闻

Skip to content

用户中心项目登录功能

参考笔记

用户中心下 — 分享版

✔登录功能

详细设计

登录接口

  1. 接收参数:用户账户、密码​
  2. 请求类型:POST​

请求参数很长时不建议用 GET​ ​

  1. 请求体:JSON格式的数据​
  2. 返回值:用户信息(脱敏)

逻辑

image.png

编写代码

  1. UserService 编写如下代码,Alt + Enter 实现方法

image.png

  1. 进入 Impl 将 Register 的逻辑复制过来,进行修改​
  • 将 final String SALT = "yupi"; 提到前面 image.png

  • 添加 @Slf4j 注解,使用 log 【方便后续系统出现问题,到日志中查找问题】 image.png

  • 修改部分逻辑 【删除插入数据;账户不能重复修改成查询用户是否存在,放在加密之后】

Java
@Override
public User doLogin(String userAccount, String userPassword) {​
   }​
   if(userAccount.length() < 4){​
      return null;​
   }​
   if(userPassword.length() < 8){​
      return null;​
   }​

   //账户不能包含特殊字符​
   String validPattern = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";​
   Matcher matcher = Pattern.compile(validPattern).matcher(userAccount);​
   if (matcher.find()) {​
      return null;​
   }​

   /* 2.加密 */
   String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());​
   //查询用户是否存在​
   QueryWrapper<User> queryWrapper = new QueryWrapper<>();​
   queryWrapper.eq("userAccount",userAccount);​
   queryWrapper.eq("userPassword",encryptPassword);​
   User user = userMapper.selectOne(queryWrapper);​
   if (user == null) {​
      log.info("user login failed,userAccount cannot match userPassword");​
      return null;​
   }​
   return user;​
}

上面查询用户是否存在的代码逻辑是存在问题的​ 如果用户的 isDelete 字段是删除状态,能否查出来呢?

MyBatis-Plus 逻辑删除 @TableLogic注解

要删除一条数据时,不是真正的删除,而是将数据库中的某个字段从 0 置为 1 表示数据失效,无法查询到

  1. 在 application.yml 中配置 MyBatis-Plus 的全局逻辑删除属性:
yml
mybatis-plus:​
  global-config:​
    db-config:​
      logic-delete-field: isDelete # 全局逻辑删除字段名​
      logic-delete-value: 1 # 逻辑已删除值​
      logic-not-delete-value: 0 # 逻辑未删除值
  1. User 实体类中 为 isDelete 字段添加 @TableLogic 注解

该注解用于标记实体类中的字段作为逻辑删除字段。逻辑删除是一种数据管理策略,它不是真正地从数据库中删除记录,而是在记录中标记该记录为已删除状态。通过使用@TableLogic注解,MyBatis-Plus 可以在查询、更新和删除操作中自动处理逻辑删除字段的值。

Java
import com.baomidou.mybatisplus.annotation.TableLogic;​

public class User {​
    // 其他字段...​

    @TableLogic
    private Integer isDelete;​
}

如何知道是哪个用户登陆了?​ (JavaWeb)

  1. 连接服务器端后,得到一个 session 状态(匿名会话),返回给前端​
  2. 登陆成功后,得到了登陆成功的 session ,并且给该 session 设置一些值(比如用户信息),返回给前端一个设置 cookie 的“命令” ​
    • session ⇒ cookie​
  3. 前端接收到后端的命令后,设置 cookie ,保存到浏览器内​
  4. 前端再次请求后端的时候(相同的域名),在请求头中带上 cookie去请求​
  5. 后端拿到前端传来的 cookie ,找到对应的 session​
  6. 后端从 session 中可以取出基于该 session 存储的变量(用户的登陆信息、登录名)

【Cookie & Session 相关知识了解】

image.png

代码编写

  1. UserService 与 UserServiceImpl 中添加 HttpServletRequest request

image.png

image.png

  1. 继续在 Impl 中编写代码
  • 记录用户的登录态 image.png

image.png

  • 用户脱敏 image.png

image.png

  1. 完整代码
Java
@Override
public User doLogin(String userAccount, String userPassword, HttpServletRequest request) {​
   queryWrapper.eq("userAccount",userAccount);​
   queryWrapper.eq("userPassword",encryptPassword);​
   User user = userMapper.selectOne(queryWrapper);​
   //用户不存在​
   if (user == null) {​
      log.info("user login failed,userAccount cannot match userPassword");​
      return null;​
   }​

   /* 3.用户脱敏 */
   User safetyUser = new User();​
   safetyUser.setId(user.getId());​
   safetyUser.setUsername(user.getUsername());​
   safetyUser.setUserAccount(user.getUserAccount());​
   safetyUser.setAvatarUrl(user.getAvatarUrl());​
   safetyUser.setGender(user.getGender());​
   safetyUser.setPhone(user.getPhone());​
   safetyUser.setEmail(user.getEmail());​
   safetyUser.setUserStatus(user.getUserStatus());​
   safetyUser.setCreateTime(user.getCreateTime());​

   /* 4.记录用户的登录态 */
       request.getSession().setAttribute(USER_LOGIN_STATE,safetyUser);​

   return safetyUser;​
}

后端-接口开发及测试

控制层Controller封装请求

application.yml 指定接口全局 api 【也可以可以等 代理这块去做】

yml
servlet:​
    context-path: /api

@RestController适用于编写restful风格的api,返回值默认为json类型​ controller 层倾向于对请求参数本身的校验不涉及业务逻辑本身(越少越好)​ service 层是对业务逻辑的校验(有可能被 controller 之外的类调用)

  1. Controller 包下新建 UserController.java ,​
  • 添加 @RestController 注解(这个类中所有的请求的接口返回值,相应的数据类型都是 application json​
  • 添加 @RequestMapping 注解(定义请求的路径)
JAVA

@RestController
@RequestMapping("/user")​
public class UserController {​

}
  1. 下载插件 Auto filling Java call arguments
  2. UserController 中编写 register请求
  • 编写注册请求 image.png

  • 封装专门用来接收请求参数的对象 model.domain 包建立一个 request 包,新建 UserRegisterRequest.java 类

继承 Serializable (序列化),打上注解

image.png

实现序列化,添加参数,打上 @lombok 注解(生成get、set方法)

image.png

  • 回到 UserController

引用 UserRegisterRequest ;打上 @RequestBody 注解(使UserRegisterRequest与前端传来的参数能够对应);判断是否为空

image.png

  • 完善代码逻辑
Java
@PostMapping("/register")​
public Long userRegister(@RequestBody UserRegisterRequest userRegisterRequest){​
   if (userRegisterRequest == null) {​
      return null;​
   }​
   String userAccount = userRegisterRequest.getUserAccount();​
   String userPassword = userRegisterRequest.getUserPassword();​
   String checkPassword = userRegisterRequest.getCheckPassword();​
   if(StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)){​
      return null;​
   }​
   return userService.userRegister(userAccount, userPassword, checkPassword);​
}
  1. UserController 中编写 login 请求​
  • 复制 register 请求,进行修改即可【重构 UserService 中的 doLogin 方法为 userLogin 方法】
Java
@PostMapping("/login")​
public User userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request){​
   if (userLoginRequest == null) {​
      return null;​
   }​
   String userAccount = userLoginRequest.getUserAccount();​
   String userPassword = userLoginRequest.getUserPassword();​
   if(StringUtils.isAnyBlank(userAccount, userPassword)){​
      return null;​
   }​
   return userService.userLogin(userAccount, userPassword,request);​
}
  • model.domain 包下面的 request 包,新建 UserLoginRequest.java 类(复制粘贴 UserRegisterRequest.java 删除其中的 checkPassword 即可)
Java
/**​
 * 用户登录请求体​
 *​
 * @Author ***​
 */
@Data
public class UserLoginRequest implements Serializable {​

private static final long serialVersionUID = 你生成的序列号;​

private String userAccount;​

private String userPassword;​
}
  1. 测试
  • 测试工具(两种方式打开)

image.png

image.png

  • 删除 GET 请求,生成 POST 请求并修改

image.png

  • Debug 方式启动项目

image.png

  • 打断点测试​

image.png

image.png

image.png

  • 测试完成

image.png

image.png

  • 再测一下逻辑删除

    • 数据库中把 yupi 的 isDelete 字段改为 1 image.png
  • 启动 POST 请求,测试完成

image.png