文章目錄
- 數據庫
- 數據庫設計
- 配置 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(); } }
}