feat(server.tests.test5): 新增 server 实验5

This commit is contained in:
2025-11-18 13:35:30 +08:00
parent 84b4770d5a
commit d0acf5a36d
9 changed files with 1095 additions and 1 deletions

View File

@@ -17,5 +17,6 @@
├── test1 # 实验1
├── test2 # 实验2
├── test3 # 实验3
── test4 # 实验4
── test4 # 实验4
└── test5 # 实验5
```

2
Server/tests/test5/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules
pnpm-lock.yaml

View File

@@ -0,0 +1,21 @@
### 实验 5
- 创建数据表
```mysql
-- 插件用户表
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
gender ENUM('male','female') NOT NULL,
hobbies TEXT,
city TEXT,
description TEXT
)
```
- 导入 api 到 apifox
apifox 导出数据: [apifox 导出数据文件](./Server.apifox.json)

View File

@@ -0,0 +1,681 @@
{
"apifoxProject": "1.0.0",
"$schema": {
"app": "apifox",
"type": "project",
"version": "1.2.0"
},
"info": {
"name": "Server",
"description": "",
"mockRule": {
"rules": [],
"enableSystemRule": true
}
},
"apiCollection": [
{
"name": "根目录",
"id": 70829727,
"auth": {},
"securityScheme": {},
"parentId": 0,
"serverId": "",
"description": "",
"identityPattern": {
"httpApi": {
"type": "methodAndPath",
"bodyType": "",
"fields": []
}
},
"shareSettings": {},
"visibility": "SHARED",
"moduleId": 6526371,
"preProcessors": [
{
"id": "inheritProcessors",
"type": "inheritProcessors",
"data": {}
}
],
"postProcessors": [
{
"id": "inheritProcessors",
"type": "inheritProcessors",
"data": {}
}
],
"inheritPostProcessors": {},
"inheritPreProcessors": {},
"items": [
{
"name": "test3",
"id": 70832123,
"auth": {},
"securityScheme": {},
"parentId": 0,
"serverId": "",
"description": "",
"identityPattern": {
"httpApi": {
"type": "inherit",
"bodyType": ""
}
},
"shareSettings": {},
"visibility": "INHERITED",
"moduleId": 6526371,
"preProcessors": [
{
"id": "inheritProcessors",
"type": "inheritProcessors",
"data": {}
}
],
"postProcessors": [
{
"id": "inheritProcessors",
"type": "inheritProcessors",
"data": {}
}
],
"inheritPostProcessors": {},
"inheritPreProcessors": {},
"items": [
{
"name": "提升部分【一】-显示平均成绩",
"api": {
"id": "374633188",
"method": "get",
"path": "http://127.0.0.1:3000/showScoure",
"parameters": {},
"auth": {},
"securityScheme": {},
"commonParameters": {
"query": [],
"body": [],
"cookie": [],
"header": []
},
"responses": [
{
"id": "187910458",
"code": 200,
"name": "成功",
"headers": [],
"jsonSchema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"avg": {
"type": "integer"
}
},
"required": [
"name",
"avg"
]
}
},
"description": "",
"contentType": "json",
"mediaType": ""
}
],
"responseExamples": [],
"requestBody": {
"type": "none",
"parameters": [],
"mediaType": "",
"examples": [],
"oasExtensions": ""
},
"description": "",
"tags": [],
"status": "developing",
"serverId": "",
"operationId": "",
"sourceUrl": "",
"ordering": 20,
"cases": [],
"mocks": [],
"customApiFields": "{}",
"advancedSettings": {
"disabledSystemHeaders": {}
},
"mockScript": {},
"codeSamples": [],
"commonResponseStatus": {},
"responseChildren": [],
"visibility": "INHERITED",
"moduleId": 6526371,
"oasExtensions": "",
"type": "http",
"preProcessors": [],
"postProcessors": [],
"inheritPostProcessors": {},
"inheritPreProcessors": {}
}
},
{
"name": "提升部分【二】",
"api": {
"id": "374632248",
"method": "get",
"path": "http://127.0.0.1:3000/mny",
"parameters": {},
"auth": {},
"securityScheme": {},
"commonParameters": {
"query": [],
"body": [],
"cookie": [],
"header": []
},
"responses": [
{
"id": "108008247",
"code": 200,
"name": "成功",
"headers": [],
"jsonSchema": {
"type": "object",
"properties": {}
},
"description": "",
"contentType": "json",
"mediaType": ""
}
],
"responseExamples": [],
"requestBody": {
"type": "none",
"parameters": [],
"mediaType": "",
"examples": [],
"oasExtensions": ""
},
"description": "",
"tags": [],
"status": "developing",
"serverId": "",
"operationId": "",
"sourceUrl": "",
"ordering": 10,
"cases": [],
"mocks": [],
"customApiFields": "{}",
"advancedSettings": {
"disabledSystemHeaders": {}
},
"mockScript": {},
"codeSamples": [],
"commonResponseStatus": {},
"responseChildren": [],
"visibility": "INHERITED",
"moduleId": 6526371,
"oasExtensions": "",
"type": "http",
"preProcessors": [],
"postProcessors": [],
"inheritPostProcessors": {},
"inheritPreProcessors": {}
}
},
{
"name": "提升部分【一】-显示对应name数据",
"api": {
"id": "374640421",
"method": "get",
"path": "http://127.0.0.1:3000/myScoure",
"parameters": {
"query": [
{
"id": "CmAc8vX0mS",
"name": "name",
"example": "zs",
"required": false,
"description": "",
"enable": true,
"type": "string"
}
]
},
"auth": {},
"securityScheme": {},
"commonParameters": {
"query": [],
"body": [],
"cookie": [],
"header": []
},
"responses": [
{
"id": "165586872",
"code": 200,
"name": "成功",
"headers": [],
"jsonSchema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"course": {
"type": "string"
},
"score": {
"type": "integer"
}
},
"required": [
"name",
"course",
"score"
]
}
},
"description": "",
"contentType": "json",
"mediaType": ""
}
],
"responseExamples": [],
"requestBody": {
"type": "none",
"parameters": [],
"mediaType": "",
"examples": [],
"oasExtensions": ""
},
"description": "",
"tags": [],
"status": "developing",
"serverId": "",
"operationId": "",
"sourceUrl": "",
"ordering": 30,
"cases": [],
"mocks": [],
"customApiFields": "{}",
"advancedSettings": {
"disabledSystemHeaders": {}
},
"mockScript": {},
"codeSamples": [],
"commonResponseStatus": {},
"responseChildren": [],
"visibility": "INHERITED",
"moduleId": 6526371,
"oasExtensions": "",
"type": "http",
"preProcessors": [],
"postProcessors": [],
"inheritPostProcessors": {},
"inheritPreProcessors": {}
}
}
]
},
{
"name": "test5",
"id": 71447739,
"auth": {},
"securityScheme": {},
"parentId": 0,
"serverId": "",
"description": "",
"identityPattern": {
"httpApi": {
"type": "inherit",
"bodyType": "",
"fields": []
}
},
"shareSettings": {},
"visibility": "INHERITED",
"moduleId": 6526371,
"preProcessors": [
{
"id": "inheritProcessors",
"type": "inheritProcessors",
"data": {}
}
],
"postProcessors": [
{
"id": "inheritProcessors",
"type": "inheritProcessors",
"data": {}
}
],
"inheritPostProcessors": {},
"inheritPreProcessors": {},
"items": [
{
"name": "register",
"api": {
"id": "378061737",
"method": "post",
"path": "http://127.0.0.1:3000/register",
"parameters": {},
"auth": {},
"securityScheme": {},
"commonParameters": {
"query": [],
"body": [],
"cookie": [],
"header": []
},
"responses": [
{
"id": "152284178",
"code": 200,
"name": "成功",
"contentType": "html"
}
],
"responseExamples": [],
"requestBody": {
"type": "application/json",
"parameters": [],
"jsonSchema": {
"type": "object",
"properties": {}
},
"mediaType": "",
"examples": [
{
"mediaType": "application/json",
"value": "{\r\n \"username\": \"aa\",\r\n \"password\": \"abcabc\",\r\n \"email\": \"abc@email.com\",\r\n \"gender\": \"male\",\r\n \"hobbies\": [\r\n \"听音乐\",\r\n \"玩游戏\"\r\n ],\r\n \"city\": \"重庆\",\r\n \"description\": \"爱坤坤\"\r\n}"
}
],
"oasExtensions": ""
},
"description": "",
"tags": [],
"status": "developing",
"serverId": "",
"operationId": "",
"sourceUrl": "",
"ordering": 10,
"cases": [],
"mocks": [],
"customApiFields": "{}",
"advancedSettings": {
"disabledSystemHeaders": {}
},
"mockScript": {},
"codeSamples": [],
"commonResponseStatus": {},
"responseChildren": [],
"visibility": "INHERITED",
"moduleId": 6526371,
"oasExtensions": "",
"type": "http",
"preProcessors": [],
"postProcessors": [],
"inheritPostProcessors": {},
"inheritPreProcessors": {}
}
},
{
"name": "login",
"api": {
"id": "378062412",
"method": "post",
"path": "http://127.0.0.1:3000/login",
"parameters": {},
"auth": {},
"securityScheme": {},
"commonParameters": {
"query": [],
"body": [],
"cookie": [],
"header": []
},
"responses": [
{
"id": "199370297",
"code": 200,
"name": "成功",
"jsonSchema": {
"type": "object",
"properties": {}
},
"contentType": "json"
}
],
"responseExamples": [],
"requestBody": {
"type": "application/json",
"parameters": [],
"jsonSchema": {
"type": "object",
"properties": {}
},
"mediaType": "",
"examples": [
{
"mediaType": "application/json",
"value": "{\r\n \"username\": \"aa\",\r\n \"password\": \"abcabc\"\r\n}"
}
],
"oasExtensions": ""
},
"description": "",
"tags": [],
"status": "developing",
"serverId": "",
"operationId": "",
"sourceUrl": "",
"ordering": 20,
"cases": [],
"mocks": [],
"customApiFields": "{}",
"advancedSettings": {
"disabledSystemHeaders": {}
},
"mockScript": {},
"codeSamples": [],
"commonResponseStatus": {},
"responseChildren": [],
"visibility": "INHERITED",
"moduleId": 6526371,
"oasExtensions": "",
"type": "http",
"preProcessors": [],
"postProcessors": [],
"inheritPostProcessors": {},
"inheritPreProcessors": {}
}
},
{
"name": "update-password",
"api": {
"id": "378062857",
"method": "post",
"path": "http://127.0.0.1:3000/update-password",
"parameters": {},
"auth": {},
"securityScheme": {},
"commonParameters": {
"query": [],
"body": [],
"cookie": [],
"header": []
},
"responses": [
{
"id": "190849250",
"code": 200,
"name": "成功",
"headers": [],
"jsonSchema": {
"type": "object",
"properties": {}
},
"description": "",
"contentType": "json",
"mediaType": ""
}
],
"responseExamples": [],
"requestBody": {
"type": "application/json",
"parameters": [],
"jsonSchema": {
"type": "object",
"properties": {}
},
"mediaType": "",
"examples": [
{
"mediaType": "application/json",
"value": "{\r\n \"username\": \"aa\",\r\n \"currentPassword\": \"abcabc\",\r\n \"newPassword\": \"abcabc\"\r\n}"
}
],
"oasExtensions": ""
},
"description": "",
"tags": [],
"status": "developing",
"serverId": "",
"operationId": "",
"sourceUrl": "",
"ordering": 30,
"cases": [],
"mocks": [],
"customApiFields": "{}",
"advancedSettings": {
"disabledSystemHeaders": {}
},
"mockScript": {},
"codeSamples": [],
"commonResponseStatus": {},
"responseChildren": [],
"visibility": "INHERITED",
"moduleId": 6526371,
"oasExtensions": "",
"type": "http",
"preProcessors": [],
"postProcessors": [],
"inheritPostProcessors": {},
"inheritPreProcessors": {}
}
}
]
}
]
}
],
"socketCollection": [],
"docCollection": [],
"webSocketCollection": [],
"socketIOCollection": [],
"responseCollection": [
{
"_databaseId": 7836150,
"updatedAt": "2025-11-11T02:38:06.000Z",
"name": "根目录",
"type": "root",
"children": [],
"moduleId": 6526371,
"parentId": 0,
"id": 7836150,
"ordering": [],
"items": []
}
],
"schemaCollection": [
{
"id": 17182762,
"name": "根目录",
"visibility": "SHARED",
"moduleId": 6526371,
"items": [],
"ordering": []
}
],
"securitySchemeCollection": [
{
"id": 2464141,
"moduleId": 6526371,
"name": "根目录",
"items": [],
"ordering": []
}
],
"requestCollection": [
{
"name": "根目录",
"children": [],
"ordering": [
"requestFolder.7895936"
],
"items": []
}
],
"apiTestCaseCollection": [
{
"name": "Root",
"children": [],
"items": []
}
],
"testCaseReferences": [],
"environments": [],
"commonScripts": [],
"databaseConnections": [],
"globalVariables": [],
"commonParameters": null,
"projectSetting": {
"id": "7426031",
"auth": {},
"securityScheme": {},
"gateway": [],
"language": "zh-CN",
"apiStatuses": [
"developing",
"testing",
"released",
"deprecated"
],
"mockSettings": {},
"preProcessors": [],
"postProcessors": [],
"advancedSettings": {
"enableJsonc": false,
"enableBigint": false,
"responseValidate": true,
"enableTestScenarioSetting": false,
"enableYAPICompatScript": false,
"isDefaultUrlEncoding": 2,
"publishedDocUrlRules": {
"defaultRule": "RESOURCE_KEY_ONLY",
"resourceKeyStandard": "NEW"
}
},
"initialDisabledMockIds": [],
"servers": [
{
"id": "default",
"name": "默认服务"
}
],
"cloudMock": {
"security": "free",
"enable": false,
"tokenKey": "apifoxToken"
}
},
"customFunctions": [],
"projectAssociations": []
}

106
Server/tests/test5/index.js Normal file
View File

@@ -0,0 +1,106 @@
const express = require("express")
const mysql = require("mysql2")
const cors = require("cors")
const app = express()
const port = 3000
const db = mysql.createConnection({
host: "127.0.0.1",
port: 3306,
user: "root",
password: "123456",
database: "express_db"
})
db.connect((err) => {
if (err) {
console.log("Error connect to MySQL database:", err);
return;
}
console.log("Connected to MySQL database");
})
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(cors({
origin: "http://127.0.0.1:3000",
method: ["GET", "POST"],
allowedHeaders: ['Content-Type', "Authorization"]
}))
app.use(express.static("public"))
app.options('/login', cors());
app.post('/register', (req, res) => {
const { username, password, email, gender, hobbies, city, description } = req.body;
const hobbiesStr = hobbies ? hobbies.join(",") : "";
const sql = 'INSERT INTO users (username, password, email, gender, hobbies, city, description) VALUES (?,?,?,?,?,?,?)'
const values = [username, password, email, gender, hobbiesStr, city, description]
db.query(sql, values, (err, result) => {
if (err) {
console.error('Error inserting data into MySQL database:', err);
res.status(500).send("Error inserting data into MySQL database");
return;
}
console.log("inserting data successful!");
res.send("Register successful")
})
})
app.post("/login", (req, res) => {
const { username, password } = req.body;
const sql = 'SELECT * FROM users WHERE username = ? AND password = ?';
const values = [username, password];
db.query(sql, values, (err, result) => {
if (err) {
console.error("Error querying the database:", err);
res.status(500).send("Error querying the database");
return;
}
if (result.length > 0) {
console.log('Login successful');
res.send('Login successful');
} else {
console.log("Login failed");
res.send("Login failed");
}
})
})
app.post("/update-password", (req, res) => {
const { username, currentPassword, newPassword } = req.body;
const sqlCheck = 'SELECT * FROM users WHERE username = ? AND password = ?';
const checkValues = [username, currentPassword];
db.query(sqlCheck, checkValues, (err, result) => {
if (err) {
console.error("Error querying the database:", err);
res.status(500).send("Error querying the database");
return;
}
if (result.length == 0) {
console.log("当前密码输入错误");
res.status(400).send("Current password is incorret");
return;
}
const updateSql = "UPDATE users SET password = ? WHERE username = ?";
const updateValue = [newPassword, username];
db.query(updateSql, updateValue, (err2, result2) => {
if (err2) {
console.error("Error updating user password:", err2);
res.status(500).send('Error updating user password');
return;
}
console.log(result2);
console.log("User password update successful");
res.send("User password update successful")
})
})
})
app.listen(port, () => {
console.log(`Server is running: http://127.0.0.1:${port}`);
})

View File

@@ -0,0 +1,18 @@
{
"name": "test5",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.14.0",
"dependencies": {
"cors": "^2.8.5",
"express": "^5.1.0",
"mysql2": "^3.15.3"
}
}

View File

@@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body,
html {
margin: 0;
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
form {
display: flex;
flex-direction: column;
width: 280px;
gap: 12px;
text-align: center;
}
input {
padding: 8px;
font-size: 15px;
width: 100%;
box-sizing: border-box;
}
button {
padding: 10px;
font-size: 16px;
cursor: pointer;
}
</style>
<title>Login</title>
</head>
<body>
<form id="loginForm">
<input type="text" id="username" placeholder="请输入用户名">
<input type="password" id="password" placeholder="请输入密码">
<button type="button" id="loginBtn">登录</button>
</form>
<script>
document.getElementById("loginBtn").addEventListener("click", login);
async function login() {
const username = document.getElementById("username").value.trim();
const password = document.getElementById("password").value.trim();
if (!username || !password) {
alert("请输入用户名和密码");
return;
}
const res = await fetch("http://localhost:3000/login", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ username, password })
});
const data = await res.text();
alert(data);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,106 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register</title>
<style>
body,
html {
margin: 0;
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
form {
display: flex;
flex-direction: column;
width: 280px;
gap: 12px;
}
input,
select,
textarea {
padding: 8px;
font-size: 15px;
}
button {
padding: 10px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<form id="registerForm">
<input id="username" type="text" placeholder="用户名" required>
<input id="password" type="password" placeholder="密码" required>
<input id="email" type="email" placeholder="邮箱" required>
<select id="gender">
<option value="male"></option>
<option value="female"></option>
</select>
<input id="hobbies" type="text" placeholder="爱好(用逗号分隔,例如:听音乐,玩游戏)">
<input id="city" type="text" placeholder="城市,例如:重庆">
<textarea id="description" rows="3" placeholder="自我介绍"></textarea>
<button type="button" id="registerBtn">注册</button>
</form>
<script>
document.getElementById("registerBtn").addEventListener("click", register);
async function register() {
const username = document.getElementById("username").value.trim();
const password = document.getElementById("password").value.trim();
const email = document.getElementById("email").value.trim();
const gender = document.getElementById("gender").value;
const hobbiesInput = document.getElementById("hobbies").value.trim();
const city = document.getElementById("city").value.trim();
const description = document.getElementById("description").value.trim();
if (!username || !password || !email) {
alert("请填写必填字段:用户名、密码、邮箱");
return;
}
const hobbies = hobbiesInput ? hobbiesInput.split(",").map(i => i.trim()) : [];
const payload = {
username,
password,
email,
gender,
hobbies,
city,
description
};
const res = await fetch("http://localhost:3000/register", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
const data = await res.text(); // 后端是字符串
alert(data);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Change Password</title>
<style>
body,
html {
margin: 0;
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
form {
display: flex;
flex-direction: column;
width: 280px;
gap: 12px;
}
input {
padding: 8px;
font-size: 15px;
}
button {
padding: 10px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<form id="changePwdForm">
<input id="username" type="text" placeholder="用户名" required>
<input id="currentPassword" type="password" placeholder="当前密码" required>
<input id="newPassword" type="password" placeholder="新密码" required>
<button type="button" id="changePwdBtn">修改密码</button>
</form>
<script>
document.getElementById("changePwdBtn").addEventListener("click", changePassword);
async function changePassword() {
const username = document.getElementById("username").value.trim();
const currentPassword = document.getElementById("currentPassword").value.trim();
const newPassword = document.getElementById("newPassword").value.trim();
if (!username || !currentPassword || !newPassword) {
alert("请填写所有字段");
return;
}
const payload = {
username,
currentPassword,
newPassword
};
const res = await fetch("http://localhost:3000/update-password", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
const data = await res.text(); // 返回字符串
alert(data);
}
</script>
</body>
</html>