[网页五子棋][用户模块]数据库设计和配置(MyBatis)、约定前后端交互接口、服务器开发
文章目录
- 数据库
- 数据库设计
- 配置 MyBatis
- 1. Spring 配置
- 2. 创建实体类
- 3. 创建 Mapper 接口
- 4. 使用 MyBatis
 
 
- 约定前后端交互接口
- 登录接口
- 注册接口
- 获取用户信息
 
- 服务器开发
- login
- register
- getUserInfo
- 完整代码
 
数据库
数据库设计
完成注册登录以及用户分数管理
- 使用数据库来保存上述用户信息
创建 java_gobang 数据库, user 表,表示用户信息和分数信息
create database if not exists java_gobang;  use java_gobang;  drop table if exists user;  
create table user (  userId int primary key auto_increment,  username varchar(50) unique,  password varchar(50),  score int,         -- 天梯积分  totalCount int,    -- 比赛总场数  winCount int       -- 获胜场数  
);  insert into user values (null, 'zhangsan', '123', 1000, 0, 0);  
insert into user values (null, 'lisi', '123', 1000, 0, 0);  
insert into user values (null, 'wangwu', '123', 1000, 0, 0);
配置 MyBatis
使用 MyBatis 来连接并操作我们的数据库
1. Spring 配置
修改 Spring 的配置文件,使用数据库可以被连接上
spring:  application:  name: java_gobang  datasource:  url: jdbc:mysql://127.0.0.1:3306/java_gobang?characterEncoding=utf8&useSSL=false  username: root  password: 20230153018  driver-class-name: com.mysql.cj.jdbc.Driver  mybatis:  mapper-locations: classpath:mapper/**Mapper.xml
- 如果 driver-class-name报错,可能是没有引入Maven依赖的原因
2. 创建实体类
创建一个实体类:用户
package org.example.model;  public class User {  private int userId;  private String username;  private String password;  private int score;  private int totalCount;  private int winCount;  public int getUserId() {  return userId;  }  public void setUserId(int userId) {  this.userId = userId;  }  public String getUsername() {  return username;  }  public void setUsername(String username) {  this.username = username;  }  public String getPassword() {  return password;  }  public void setPassword(String password) {  this.password = password;  }  public int getScore() {  return score;  }  public void setScore(int score) {  this.score = score;  }  public int getTotalCount() {  return totalCount;  }  public void setTotalCount(int totalCount) {  this.totalCount = totalCount;  }  public int getWinCount() {  return winCount;  }  public void setWinCount(int winCount) {  this.winCount = winCount;  }  
}
3. 创建 Mapper 接口
package org.example.model;  /**  * 接口里面创建一些典型的方法  */  
public interface UserMapper {  // 往数据库中插入一个用户,用于注册功能  void insert(User user);  // 根据用户名,来查询用户的详细信息,用于登录功能  User selectByName(String userName);  
}
4. 使用 MyBatis
实现 MyBatis 的相关 xml 配置文件,来自动实现数据库操作
实现 UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace="org.example.java_gobang.model.UserMapper">  <insert id="insert">  insert into user values(null, #{username}, #{password}, 1000, 0, 0);  </insert>  <select id="selectByName" resultType="org.example.java_gobang.model.User">  select * from user where username = #{username};  </select>  
</mapper>
约定前后端交互接口
登录接口
请求:
- POST /login HTTP/1.1
- Content-Type: application/x-222-form-urlencoded
- username=zhangsan&password=123
响应:
- HTTP/1.1 200 OK
- Content-Type: application/json
 {
 userId: 1,
 username: ‘zhangsan’,
 score: 1000,
 totalCount: 0,
 winCount: 0
 }
- 如果登录失败,就返回一个无效的 user对象- 比如,这里的每个属性都是空着的,像 userId => 0
 
- 比如,这里的每个属性都是空着的,像 
注册接口
请求:
- POST /register HTTP/1.1
- Content-Type: application/x-www-form-urlencoded
- username=zhangsan&password=123
响应:
- HTTP/1.1 200 OK
- Content-Type: application/json
 {
 userId: 1,
 username: ‘zhangsan’,
 score: 1000,
 totalCount: 0,
 winCount: 0
 }
前后端交互的接口,在约定的时候,是有很多种交互方式的
- 这里约定好了之后,后续的后端/前端代码,都要严格地遵守这个约定来写代码
获取用户信息
从服务器获取到当前登录用户的信息
- 程序运行过程中,用户登录了之后,让客户端随时通过这个接口,来访问服务器,获取到自身的信息
请求:
- GET /userInfo HTTP/1.1
响应:
- HTTP/1.1 200 OK
- COntent-Type: application/json
 {
 userId: 1,
 username: ‘zhangsan’,
 score: 1000,
 totalCount: 0,
 winCount: 0
 }
服务器开发
创建 api.UserAPI 类,主要实现三个方法:
- login:用来实现登录逻辑
- register:用来实现注册逻辑
- getUserInfo:用来实现登录成功后显示用户分数的信息
login
在登录的时候,我们要做的关键操作就是:
- 根据用户传进来的 username,去数据库里面查一下,看查到的结果能不能和传入进来的password匹配- 匹配:登陆成功
- 不匹配:登录失败
 
@PostMapping("/login")  
@ResponseBody  
public Object login(String username, String password, HttpServletRequest req) {  // 关键操作,就是根据 username 去数据库中进行查找,  // 如果能找到匹配的用户,并且密码也一直,就认为登录成功  User user = userMapper.selectByName(username); System.out.println("[login] username=" + username);  if (user == null || !user.getPassword().equals(password)) {  // 登录失败  System.out.println("登录失败!");  return new User();  }  HttpSession httpSession = req.getSession(true);  httpSession.setAttribute("user", user);  return user;  
}
- HttpServletRequest:可以通过这个对象获取或创建- Session,以及访问其他- HTTP属性
- getSession(true):- 如果当前请求中没有带上已有的 Session ID,或者Session已过期,就会创建一个新的HttpSession对象
- 如果存在有效的 Session,会返回当前Session
 
- 如果当前请求中没有带上已有的 
- getSession(false):- 如果当前请求没有有效的 Session,会返回null,不会创建新的Session
 
- 如果当前请求没有有效的 
- httpSession.setAttribute("user", user)- 向 Session保存一项属性,键是“user”,值是当前登录的用户对象
- 保存后,在接下来的任何请求中,只要该用户带着同一个 Session ID(通常通过cookie自动携带),就能取出这个对象
 
- 向 
register
@PostMapping("/register")  
@ResponseBody  
public Object register(String username, String password) {  try {  User user = new User();  user.setUsername(username);  user.setPassword(password);  userMapper.insert(user);  return user;  }catch (org.springframework.dao.DuplicateKeyException e) {  User user = new User();  return user;  }  
}
- } catch (org.springframework.dao.DuplicateKeyException e) {- 如果数据库表中设置了 username为唯一索引(UNIQUE),当插入一个已存在的用户名时会抛出此异常
- 这个异常来自 Spring的DataAccessException系列,专门处理数据库层的错误
 
- 如果数据库表中设置了 
getUserInfo
@GetMapping("/userInfo")  
@ResponseBody  
public Object getUserInfo(HttpServletRequest req) {  try {  HttpSession httpSession = req.getSession(false);  User user = (User) httpSession.getAttribute("user");  return user;  }catch (NullPointerException e) {  return new User();  }  
}
完整代码
package org.example.java_gobang.api;  import jakarta.annotation.Resource;  
import jakarta.servlet.http.HttpServletRequest;  
import jakarta.servlet.http.HttpSession;  
import org.example.java_gobang.model.User;  
import org.example.java_gobang.model.UserMapper;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.PostMapping;  
import org.springframework.web.bind.annotation.ResponseBody;  
import org.springframework.web.bind.annotation.RestController;  @RestController  
public class UserAPI{  @Resource  private UserMapper userMapper;  @PostMapping("/login")  @ResponseBody  public Object login(String username, String password, HttpServletRequest req) {  // 关键操作,就是根据 username 去数据库中进行查找,  // 如果能找到匹配的用户,并且密码也一直,就认为登录成功  User user = userMapper.selectByName(username);  System.out.println("[login] username=" + username);  if (user == null || !user.getPassword().equals(password)) {  // 登录失败  System.out.println("登录失败!");  return new User();  }  HttpSession httpSession = req.getSession(true);  httpSession.setAttribute("user", user);  return user;  }  @PostMapping("/register")  @ResponseBody  public Object register(String username, String password) {  try {  User user = new User();  user.setUsername(username);  user.setPassword(password);  userMapper.insert(user);  return user;  }catch (org.springframework.dao.DuplicateKeyException e) {  User user = new User();  return user;  }  }  @GetMapping("/userInfo")  @ResponseBody  public Object getUserInfo(HttpServletRequest req) {  try {  HttpSession httpSession = req.getSession(false);  User user = (User) httpSession.getAttribute("user");  return user;  }catch (NullPointerException e) {  return new User();  }  }  
}
