文章目录
- ES6须知基础知识点:
- [1. 箭头函数、模板字符串、解构赋值](#1. 箭头函数、模板字符串、解构赋值)
-
- [1. 箭头函数](#1. 箭头函数)
- [2. 模板字符串](#2. 模板字符串)
- [3. 解构赋值](#3. 解构赋值)
- [2. Promise 基础、异步操作](#2. Promise 基础、异步操作)
- [3. async/await 语法](#3. async/await 语法)
-
- [1. async 函数](#1. async 函数)
- [2. await 表达式](#2. await 表达式)
- [4. ES6 模块化](#4. ES6 模块化)
- [5. fetch/axios 请求与前后端联通基础](#5. fetch/axios 请求与前后端联通基础)
-
- 一、请求方法规范(必须遵守)
- [二、Axios 前端请求基础](#二、Axios 前端请求基础)
-
- [1. 引入 Axios](#1. 引入 Axios)
- [2. 获取前端页面数据](#2. 获取前端页面数据)
- [3. JS 创建对象](#3. JS 创建对象)
- [4. Axios 发送请求(核心语法)](#4. Axios 发送请求(核心语法))
- [5. 重要区别](#5. 重要区别)
- [6. 调试技巧](#6. 调试技巧)
- [三、跨域问题(重点 ⭐)](#三、跨域问题(重点 ⭐))
-
- [1. 错误原因](#1. 错误原因)
- [2. 同源策略](#2. 同源策略)
- [3. FastAPI 添加 CORS 中间件,解决跨域代码](#3. FastAPI 添加 CORS 中间件,解决跨域代码)
- 四、前后端交互核心逻辑
- [五、本地存储 localStorage](#五、本地存储 localStorage)
-
- [1. 特点](#1. 特点)
- [2. 使用方法](#2. 使用方法)
- [3. 使用场景](#3. 使用场景)
- [六、会话存储 sessionStorage](#六、会话存储 sessionStorage)
- 七、页面跳转
- [八、前端控制后端数据库精髓(重点 ⭐)](#八、前端控制后端数据库精髓(重点 ⭐))
- 九、页面局部刷新技巧
- 前后端联通实战案例:学生管理系统
ES6须知基础知识点:
1、ES6是 ECMAScript 在 2015 年发布的 第六个版本 的标准化的脚本程序设计语言,在日常工作中,大家习惯把 ES2015 及之后所有新版本(ES2016~ESNext)统称为 ES6,表示「现代 JS 语法」
2、ES6(ES2015+) 就是 JavaScript 本身的语法规范,因为ES6版本变更最大,传播范围最广,应用最多,所以才主要学习ES6
1. 箭头函数、模板字符串、解构赋值
1. 箭头函数
就是简写版的函数,写法更短,用 => 代替传统 function。
javascript
// 普通函数
function add(a, b) {
return a + b;
}
// 箭头函数
const add = (a, b) => a + b;
2. 模板字符串
!!!注意:反引号在键盘上,是英文状态下的波浪号(`),不是单引号(')
用反引号 ` 包裹字符串,
可以直接换行 ,也能直接塞变量(不用拼接 +)。
javascript
let name = "小明";
let age = 20;
// 以前
let str = "我叫" + name + ",今年" + age + "岁";
// 模板字符串
let str = `我叫${name},今年${age}岁`;
3. 解构赋值
快速从对象 / 数组里取出数据,赋值给变量。
数组解构:
注意:
1.左边是 [],右边也必须是数组
2.数组解构取值按顺序对应
3.可以只取前面几个,后面不要
4.可以给默认值(取不到时用)
javascript
let arr = [10, 20];
let [a, b] = arr; // a=10, b=20
对象解构:
注意:
1.左边是 {},右边是对象
2.对象解构变量名必须和属性名一样,否则拿不到
3.可以改名:{原名: 新名}
4.可以给默认值
javascript
let user = { name: "小红", age: 18 };
let { name, age } = user; // name="小红", age=18
2. Promise 基础、异步操作
1. 异步操作
正常代码(同步):
一件事做完,才能做下一件。
异步操作:
不用死等这件事结束,可以先去做别的事,等这件事有结果了,再回来处理。
常见异步:
定时器 setTimeout
发送请求拿数据(ajax / 接口)
读取文件
2. Promise 基础
Promise 就是专门用来处理异步操作的工具,让异步代码更好写、更好看。
① Promise 有三种状态
pending:进行中 (还没结果)
fulfilled:成功了
rejected:失败了
状态一旦变了,就不能再改。
② 基本写法
javascript
// 1. 创建 Promise
let p = new Promise((resolve, reject) => {
// 这里放异步操作(比如定时器、请求)
setTimeout(() => {
// 成功就调用 resolve
resolve("成功数据");
// Promise状态变更为fulfilled
// 失败就调用 reject
// reject("失败原因");
// Promise状态变更为rejected
}, 1000);
});
// 2. 使用 Promise
p.then((res) => {
// 成功走这里
console.log(res);
}).catch((err) => {
// 失败走这里
console.log(err);
});
③ 核心:
resolve(...)成功 → 触发 .then()
reject(...)失败→ 触发 .catch()
④ 好处
以前异步嵌套会很乱(回调地狱),
用 Promise 可以写成链式 .then().then(),结构更清晰。
额外知识点:
1.回调地狱:
就是异步套异步,代码一直往右缩进,像金字塔,难读难改。
举例:
javascript
// 一层套一层
setTimeout(() => {
console.log(1)
setTimeout(() => {
console.log(2)
setTimeout(() => {
console.log(3)
}, 100)
}, 100)
}, 100)
总结为一句话:
回调函数里再写回调,层层嵌套 = 回调地狱
3. async/await 语法
一句话理解:
async 给函数加 "异步特权",await 是 "暂停等结果"
1. async 函数
1)返回值一定是 Promise
2)不管函数里 return 什么内容,都会自动包装成 Promise 对象。
Promise对象示例:
javascript
async function asyncFn() {
return 11;
}
console.log(asyncFn());
输出结果:

3)Promise 结果由返回值决定
简单点说:你 return 什么,外面的 Promise 就拿到什么。
4)默认是成功状态,只有两种情况会变成失败:
1.手动 throw 抛出错误
2.主动返回失败的 Promise
5)正确取值方式:
javascript
async function asyncFn() {
return Promise.resolve("输出正确");
}
两种取值方式
1.用 .then() 接收(因为本身是 Promise)
asyncFn().then(res => console.log(res));
2.用 await 取值,配合 try...catch 处理错误
注意:await只能写在async函数内
async function test() {
try {
let a = await asyncFn();
console.log(a);
} catch (error) {
console.log("捕获到错误:", error); // 这里会执行
}
}
test();
2. await 表达式
1)使用限制:必须写在被 async 修饰的函数里面。
2)使用对象:
后面一般跟 Promise 对象。
3)正常执行
直接返回 Promise 成功的结果。
4)异常处理
若 Promise 失败,会抛出异常,必须用 try...catch 捕获。
示例:
javascript
async function text() {
// 异步操作
}
async function fn() {
try {
let a = await text();
console.log(a);
} catch (error) {
console.log(error);
}
}
4. ES6 模块化
一、模块化基础概念
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
二、模块化的好处
- 防止命名冲突
命名重复时可以用as重命名,或者通过"模块名"区分,例如:user.name/goods.name - 代码复用
- 高维护性
功能集中在独立文件,改需求时只改对应文件
三、模块化基本功能和语法
模块功能主要由两个命令构成:export 和 import 。
只有被 export 暴露了的变量和函数,才能在使用 import 导入后使用。
1. export 暴露
作用:让模块对外提供功能。
给当前 JS 文件的变量 / 函数 / 对象"打标记",告诉浏览器:这些内容可以被其他文件导入使用。
(1)分别暴露
js
export let name = "张三"
(2)统一暴露
js
export { name }
(3)默认暴露
- 注意:一个文件只能有 1 个默认暴露
- 特点:导入时不用写大括号,语法更简洁;暴露的对象里不用加
let/const/function,直接写键值对
js
export default {
// 注意:不需要类型声明,没有 = 号,函数不需要写 function
name: "张三"
}
-
重要提醒:
默认暴露的内容会放在default属性里,使用时要加default:jsconsole.log(m3.default.address); m3.default.goSchool();
2. import 导入
注意:必须加 type="module",告诉浏览器这是模块化脚本。
(1)通用导入
导入整个模块,起一个别名使用:
html
<script type="module">
import * as m1 from './module1.js';
console.log(m1.name);
m1.sayHi();
</script>
(2)解构赋值导入
只导入需要的内容,不导入全部:
html
<script type="module">
import { name, sayHi } from './module1.js';
console.log(name);
sayHi();
</script>
(3)默认暴露简洁导入
只适用于默认暴露的模块:
html
<script type="module">
import m3 from './module3.js';
console.log(m3.address);
m3.goSchool();
</script>
友情提示:在以上暴露(export)与引入(import)中选取一对使用即可
推荐组合:
1.默认暴露+简洁导入
2.统一暴露+通用导入
5. fetch/axios 请求与前后端联通基础
一、请求方法规范(必须遵守)
核心注意事项
- 查询 / 获取数据 :使用
@app.get() - 创建 / 修改 / 删除数据 :使用
@app.post()/@app.put()/@app.delete()
不按规范使用会导致:
接口语义混乱、出现 422 错误、可维护性下降、网关/代理异常。
二、Axios 前端请求基础
1. 引入 Axios
在 HTML 中加入:
html
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
也可以下载axios到本地,从本地引入
2. 获取前端页面数据
通过 DOM 获取表单/输入框内容:
js
let name = document.getElementsByName('name')[0].value
let pass = document.getElementsByName('pass')[0].value
3. JS 创建对象
js
let users = {
user_name: name,
user_pass: pass
}
4. Axios 发送请求(核心语法)
js
axios({
url: "接口地址",
method: "post", // 请求方式:get/post/put/delete
data: users // post 用 data;get 用 params
}).then(result => {
// 请求成功处理
console.log(result)
}).catch(err => {
// 请求失败处理
console.log(err)
})
5. 重要区别
- POST 请求 :用
data传参 - GET 请求 :用
params传参
6. 调试技巧
多用 console.log() 打印数据,确认每一步是否正确。
三、跨域问题(重点 ⭐)
1. 错误原因
这个违背了同源策略,浏览器自动阻止网页脚本的访问,这种行为也叫做跨域
2. 同源策略
浏览器安全机制:协议、域名、端口必须完全一致。
3. FastAPI 添加 CORS 中间件,解决跨域代码
js
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# 解决跨域
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
四、前后端交互核心逻辑
前端请求 → 后端处理 → 返回数据 → 前端渲染
Axios 是前后端数据传输的桥梁。
五、本地存储 localStorage
1. 特点
- 永久存储(手动删除才消失)
- 大小约 5MB
- 只能存字符串,对象/数组必须转 JSON
2. 使用方法
js
// 存
localStorage.setItem("user", JSON.stringify(userInfo))
// 取
let data = JSON.parse(localStorage.getItem("user"))
// 删
localStorage.removeItem("user")
3. 使用场景
记住用户设置、保存登录状态、表单暂存。
六、会话存储 sessionStorage
- 临时存储,关闭浏览器/标签页自动清空
- 使用方法与 localStorage 完全一样
- 适合一次性、临时信息
七、页面跳转
js
location.href = "跳转地址"
最常用的前端页面跳转方式,会刷新页面。
八、前端控制后端数据库精髓(重点 ⭐)
- 后端接口 return 数据
- 前端 axios 通过 then(res) 接收
- 前端循环/处理数据
- 用 createElement / appendChild 动态渲染
- 前端传数据给后端 → axios 的 data
- 后端接收 → 依靠模型(User_Login_Model)
九、页面局部刷新技巧
想要无刷新更新列表/内容:
- 先用
innerHTML = ""清空旧内容 - 重新请求最新数据
- 重新渲染到页面
前后端联通实战案例:学生管理系统
前端代码:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>综合练习 - 学生管理系统</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; background-color: #f5f5f5; padding: 20px; }
.container { background-color: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h1 { text-align: center; color: #333; margin-bottom: 30px; }
.form-group { margin: 15px 0; }
input, button { padding: 10px 15px; margin: 5px; border: 1px solid #ddd; border-radius: 4px; }
input:focus { outline: none; border-color: #4CAF50; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
th { background-color: #4CAF50; color: white; }
tr:hover { background-color: #f9f9f9; }
.btn-delete { background-color: #f44336; color: white; border: none; cursor: pointer; padding: 8px 15px; }
.btn-delete:hover { background-color: #d32f2f; }
.btn-edit { background-color: #2196F3; color: white; border: none; cursor: pointer; padding: 8px 15px; }
.btn-edit:hover { background-color: #1976D2; }
.btn-primary { background-color: #4CAF50; color: white; border: none; cursor: pointer; }
.btn-primary:hover { background-color: #45a049; }
/* 模态框样式 */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.5);
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.modal-content {
background-color: #fefefe;
margin: 10% auto;
padding: 0;
border: none;
width: 450px;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from { transform: translateY(-50px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
background-color: #2196F3;
border-radius: 8px 8px 0 0;
}
.modal-header h3 {
margin: 0;
color: white;
font-size: 18px;
}
.close {
color: white;
font-size: 28px;
font-weight: bold;
cursor: pointer;
line-height: 20px;
}
.close:hover {
color: #ecf0f1;
}
.modal-body {
padding: 25px 20px;
}
.form-group label {
display: block;
margin-bottom: 6px;
font-weight: bold;
color: #555;
font-size: 14px;
}
.form-group input {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
box-sizing: border-box;
}
.form-group input[disabled] {
background-color: #ecf0f1;
color: #7f8c8d;
cursor: not-allowed;
}
.form-group input[readonly] {
background-color: #ecf0f1;
color: #7f8c8d;
cursor: not-allowed;
}
.modal-footer {
display: flex;
justify-content: flex-end;
padding: 15px 20px;
background-color: #f8f9fa;
border-radius: 0 0 8px 8px;
border-top: 1px solid #e9ecef;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-left: 10px;
transition: background-color 0.3s;
}
.btn-primary {
background-color: #2196F3;
color: white;
}
.btn-primary:hover {
background-color: #1976D2;
}
.btn-secondary {
background-color: #95a5a6;
color: white;
}
.btn-secondary:hover {
background-color: #7f8c8d;
}
.readonly-label {
color: #7f8c8d;
font-size: 12px;
margin-left: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>学生管理系统</h1>
<div class="form-group">
<input type="text" id="stuName" placeholder="姓名">
<input type="text" id="stuMajor" placeholder="专业">
<button class="btn-primary" onclick="selectStudent()">查询学生</button>
<button class="btn-primary" onclick="openAddModal()">添加学生</button>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>专业</th>
<th>操作</th>
</tr>
</thead>
<tbody id="studentTable">
</tbody>
</table>
</div>
<!-- 修改学生模态框 -->
<div id="editModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>修改学生信息</h3>
<span class="close">×</span>
</div>
<div class="modal-body">
<form id="editForm">
<div class="form-group">
<label for="editId">学生ID <span class="readonly-label">(不可修改)</span></label>
<input type="text" id="editId" name="editId" readonly>
</div>
<div class="form-group">
<label for="editName">姓名</label>
<input type="text" id="editName" name="editName" placeholder="请输入姓名">
</div>
<div class="form-group">
<label for="editAge">年龄</label>
<input type="number" id="editAge" name="editAge" placeholder="请输入年龄">
</div>
<div class="form-group">
<label for="editMajor">专业</label>
<input type="text" id="editMajor" name="editMajor" placeholder="请输入专业">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="cancelBtn">取消</button>
<button type="button" class="btn btn-primary" id="saveBtn">保存修改</button>
</div>
</div>
</div>
<!-- 添加学生模态框 -->
<div id="addModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>添加学生信息</h3>
<span class="close">×</span>
</div>
<div class="modal-body">
<form id="addForm">
<div class="form-group">
<label for="addName">姓名</label>
<input type="text" id="addName" name="addName" placeholder="请输入姓名">
</div>
<div class="form-group">
<label for="addAge">年龄</label>
<input type="number" id="addAge" name="addAge" placeholder="请输入年龄">
</div>
<div class="form-group">
<label for="addMajor">专业</label>
<input type="text" id="addMajor" name="addMajor" placeholder="请输入专业">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="cancelAddBtn">取消</button>
<button type="button" class="btn btn-primary" id="saveAddBtn">保存添加</button>
</div>
</div>
</div>
<script src="./text/js/axios.min.js"></script>
<script>
// API基础URL
const API_BASE_URL = 'http://127.0.0.1:8088';
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
loadAllStudents();
bindModalEvents();
});
// 加载所有学生
function loadAllStudents() {
axios.post(`${API_BASE_URL}/students`)
.then(response => {
console.log('数据库返回数据:', response.data);
renderTable(response.data.students);
})
.catch(error => {
console.error('加载失败:', error);
document.getElementById('studentTable').innerHTML =
'<tr><td colspan="5" style="text-align:center;color:red;">加载失败,请检查后端服务是否启动</td></tr>';
});
}
// 渲染表格
function renderTable(students) {
const tbody = document.getElementById('studentTable');
if (students.length === 0) {
tbody.innerHTML = '<tr><td colspan="5" style="text-align:center;">暂无学生数据</td></tr>';
return;
}
tbody.innerHTML = students.map(student => `
<tr>
<td>${student.id}</td>
<td>${student.name}</td>
<td>${student.age}</td>
<td>${student.major}</td>
<td>
<button class="btn-delete" onclick="deleteStudent(${student.id})">删除</button>
<button class="btn-edit" onclick="editStudent(${student.id})">修改</button>
</td>
</tr>
`).join('');
}
// 查询学生
function selectStudent() {
const name = document.getElementById('stuName').value.trim();
const major = document.getElementById('stuMajor').value.trim();
axios.post(`${API_BASE_URL}/students/query`, {
name: name || null,
major: major || null
})
.then(response => {
renderTable(response.data.students);
})
.catch(error => {
console.error('查询失败:', error);
alert('查询失败!');
});
}
// 删除学生
function deleteStudent(id) {
if (confirm('确定要删除该学生吗?此操作将从数据库中永久删除!')) {
axios.post(`${API_BASE_URL}/students/delete/${id}`)
.then(response => {
alert(response.data.message);
loadAllStudents();
})
.catch(error => {
console.error('删除失败:', error);
alert('删除失败!');
});
}
}
// 修改学生 - 打开模态框
function editStudent(id) {
axios.post(`${API_BASE_URL}/students/${id}`)
.then(response => {
const student = response.data.student;
if (student) {
document.getElementById('editId').value = student.id;
document.getElementById('editName').value = student.name;
document.getElementById('editAge').value = student.age;
document.getElementById('editMajor').value = student.major;
openModal();
} else {
alert('学生不存在!');
}
})
.catch(error => {
console.error('获取学生信息失败:', error);
alert('获取学生信息失败!');
});
}
// 模态框相关函数
function openModal() {
document.getElementById('editModal').style.display = 'block';
}
function closeModal() {
document.getElementById('editModal').style.display = 'none';
document.getElementById('editForm').reset();
}
// 保存修改
function saveEdit() {
const id = parseInt(document.getElementById('editId').value);
const name = document.getElementById('editName').value.trim();
const age = parseInt(document.getElementById('editAge').value);
const major = document.getElementById('editMajor').value.trim();
// 表单验证
if (!name) {
alert('姓名不能为空!');
return;
}
if (!age || age <= 0) {
alert('请输入有效的年龄!');
return;
}
if (!major) {
alert('专业不能为空!');
return;
}
let arr = {
id: Number(id),
name: name,
age: Number(age),
major: major
}
// 发送修改请求到数据库
axios({
url: `${API_BASE_URL}/students/update`,
method: "put",
data: arr
})
.then(response => {
alert(response.data.message);
closeModal();
loadAllStudents();
})
.catch(error => {
console.error('修改失败:', error);
alert('修改失败!');
});
}
// 打开添加模态框
function openAddModal() {
document.getElementById('addModal').style.display = 'block';
}
// 关闭添加模态框
function closeAddModal() {
document.getElementById('addModal').style.display = 'none';
document.getElementById('addForm').reset();
}
// 保存添加
function saveAdd() {
const name = document.getElementById('addName').value.trim();
const age = parseInt(document.getElementById('addAge').value);
const major = document.getElementById('addMajor').value.trim();
// 表单验证
if (!name) {
alert('姓名不能为空!');
return;
}
if (!age || age <= 0) {
alert('请输入有效的年龄!');
return;
}
if (!major) {
alert('专业不能为空!');
return;
}
// 发送添加请求到数据库
axios.put(`${API_BASE_URL}/students/create`, {
name: name,
age: age,
major: major
})
.then(response => {
alert(response.data.message);
closeAddModal();
loadAllStudents();
})
.catch(error => {
console.error('添加失败:', error);
alert('添加失败!');
});
}
// 绑定模态框事件
function bindModalEvents() {
// 修改模态框事件
document.querySelectorAll('.close')[0].onclick = closeModal;
document.getElementById('cancelBtn').onclick = closeModal;
document.getElementById('saveBtn').onclick = saveEdit;
// 添加模态框事件
document.querySelectorAll('.close')[1].onclick = closeAddModal;
document.getElementById('cancelAddBtn').onclick = closeAddModal;
document.getElementById('saveAddBtn').onclick = saveAdd;
// 点击模态框外部关闭
window.onclick = function(event) {
const editModal = document.getElementById('editModal');
const addModal = document.getElementById('addModal');
if (event.target === editModal) {
closeModal();
} else if (event.target === addModal) {
closeAddModal();
}
};
}
</script>
</body>
</html>
后端代码:
python
from fastapi import FastAPI
import uvicorn
from starlette.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List, Optional
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
app = FastAPI()
# 添加 CORS 中间件解决跨域问题
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ==================== 数据库配置 ====================
# 创建数据库连接引擎
database = "sqlite:///./students.db"
engine = create_engine(database, connect_args={"check_same_thread": False})
Session = sessionmaker(bind=engine, autoflush=False, autocommit=False)
Base = declarative_base()
# ==================== 数据库模型定义 ====================
class StudentDB(Base):
"""学生数据库模型"""
__tablename__ = "students"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(50))
age = Column(Integer)
major = Column(String(100))
# 创建数据库表
Base.metadata.create_all(bind=engine)
# ==================== API数据模型定义 ====================
class Student(BaseModel):
"""学生数据模型"""
id: int
name: str
age: int
major: str
class Config:
from_attributes = True
class StudentCreate(BaseModel):
"""创建学生请求模型"""
name: str
age: int
major: str
class StudentUpdate(BaseModel):
"""修改学生请求模型"""
id: int
name: str
age: int
major: str
class StudentQuery(BaseModel):
"""查询学生请求模型"""
name: Optional[str] = None
major: Optional[str] = None
# ==================== 辅助函数 ====================
def init_sample_data():
"""初始化示例数据"""
session = Session()
try:
# 检查是否已有数据
existing_students = session.query(StudentDB).all()
if not existing_students:
# 添加示例数据
sample_students = [
StudentDB(id=1001, name="张三", age=18, major="计算机科学与技术"),
StudentDB(id=1002, name="李四", age=19, major="软件工程"),
StudentDB(id=1003, name="王五", age=20, major="数据科学")
]
session.add_all(sample_students)
session.commit()
print("示例数据初始化成功!")
except Exception as e:
session.rollback()
print(f"初始化示例数据失败: {e}")
finally:
session.close()
# ==================== API接口定义 ====================
@app.get("/")
def read_root():
"""根路径,返回服务状态"""
return {"message": "欢迎使用学生管理系统API", "status": "running", "database": "SQLite"}
@app.post("/students")
def get_all_students():
"""
获取所有学生信息
返回:
- students: 学生列表
- total: 学生总数
"""
session = Session()
try:
students = session.query(StudentDB).all()
return {
"students": [
{
"id": s.id,
"name": s.name,
"age": s.age,
"major": s.major
} for s in students
],
"total": len(students)
}
finally:
session.close()
@app.post("/students/query")
def query_students(query: StudentQuery):
"""
根据条件查询学生信息
参数:
- name: 学生姓名(可选)
- major: 学生专业(可选)
返回:
- students: 符合条件的学生列表
- total: 符合条件的学生数量
"""
session = Session()
try:
query_obj = session.query(StudentDB)
if query.name:
query_obj = query_obj.filter(StudentDB.name.contains(query.name))
if query.major:
query_obj = query_obj.filter(StudentDB.major.contains(query.major))
students = query_obj.all()
return {
"students": [
{
"id": s.id,
"name": s.name,
"age": s.age,
"major": s.major
} for s in students
],
"total": len(students)
}
finally:
session.close()
@app.post("/students/{student_id}")
def get_student_by_id(student_id: int):
"""
根据ID查询学生信息
参数:
- student_id: 学生ID
返回:
- student: 学生信息对象
"""
session = Session()
try:
student = session.query(StudentDB).filter(StudentDB.id == student_id).first()
if student:
return {
"student": {
"id": student.id,
"name": student.name,
"age": student.age,
"major": student.major
}
}
else:
return {"message": "学生不存在"}
finally:
session.close()
@app.put("/students/create")
def create_student(student: StudentCreate):
"""
创建新学生
参数:
- name: 学生姓名
- age: 学生年龄
- major: 学生专业
返回:
- message: 创建结果消息
- student: 创建的学生信息
"""
session = Session()
try:
# 检查姓名是否已存在
existing = session.query(StudentDB).filter(StudentDB.name == student.name).first()
if existing:
return {"message": "学生姓名已存在"}
# 获取最大ID并自增
max_id = session.query(StudentDB.id).order_by(StudentDB.id.desc()).first()
new_id = (max_id[0] + 1) if max_id else 1001
# 创建新学生
new_student = StudentDB(
id=new_id,
name=student.name,
age=student.age,
major=student.major
)
session.add(new_student)
session.commit()
session.flush()
return {
"message": "创建成功",
"student": {
"id": new_student.id,
"name": new_student.name,
"age": new_student.age,
"major": new_student.major
}
}
except Exception as e:
session.rollback()
return {"message": f"创建失败: {str(e)}"}
finally:
session.close()
@app.put("/students/update")
def update_student(student: StudentUpdate):
"""
修改学生信息
参数:
- id: 学生ID(不可修改,用于定位学生)
- name: 新姓名
- age: 新年龄
- major: 新专业
返回:
- message: 修改结果消息
- student: 修改后的学生信息
"""
session = Session()
try:
# 查找学生
db_student = session.query(StudentDB).filter(StudentDB.id == student.id).first()
print(db_student)
if db_student:
# 更新学生信息
db_student.name = student.name
db_student.age = student.age
db_student.major = student.major
session.commit()
return {
"message": "修改成功",
"student": {
"id": db_student.id,
"name": db_student.name,
"age": db_student.age,
"major": db_student.major
}
}
else:
return {"message": "学生不存在"}
except Exception as e:
session.rollback()
return {"message": f"修改失败: {str(e)}"}
finally:
session.close()
@app.post("/students/delete/{student_id}")
def delete_student(student_id: int):
"""
删除学生
参数:
- student_id: 学生ID
返回:
- message: 删除结果消息
- student: 被删除的学生信息
"""
session = Session()
try:
# 查找学生
db_student = session.query(StudentDB).filter(StudentDB.id == student_id).first()
if db_student:
deleted_info = {
"id": db_student.id,
"name": db_student.name,
"age": db_student.age,
"major": db_student.major
}
session.delete(db_student)
session.commit()
return {
"message": "删除成功",
"student": deleted_info
}
else:
return {"message": "学生不存在"}
except Exception as e:
session.rollback()
return {"message": f"删除失败: {str(e)}"}
finally:
session.close()
# 程序入口
if __name__ == "__main__":
# 初始化示例数据
init_sample_data()
print("学生管理系统API服务启动中...")
print("服务地址: http://127.0.0.1:8088")
print("API文档: http://127.0.0.1:8088/docs")
print("数据库: SQLite (students.db)")
uvicorn.run(app, host="127.0.0.1", port=8088)