零基础-从ESS6基础到前后端联通实战

文章目录

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 模块化

一、模块化基础概念

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。

二、模块化的好处

  1. 防止命名冲突
    命名重复时可以用 as 重命名,或者通过"模块名"区分,例如:user.name / goods.name
  2. 代码复用
  3. 高维护性
    功能集中在独立文件,改需求时只改对应文件

三、模块化基本功能和语法

模块功能主要由两个命令构成:exportimport

只有被 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

    js 复制代码
    console.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 = "跳转地址"

最常用的前端页面跳转方式,会刷新页面。


八、前端控制后端数据库精髓(重点 ⭐)

  1. 后端接口 return 数据
  2. 前端 axios 通过 then(res) 接收
  3. 前端循环/处理数据
  4. 用 createElement / appendChild 动态渲染
  5. 前端传数据给后端 → axios 的 data
  6. 后端接收 → 依靠模型(User_Login_Model)

九、页面局部刷新技巧

想要无刷新更新列表/内容:

  1. 先用 innerHTML = "" 清空旧内容
  2. 重新请求最新数据
  3. 重新渲染到页面

前后端联通实战案例:学生管理系统

前端代码:

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">&times;</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">&times;</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)
相关推荐
SAP小崔说事儿2 小时前
SAP B1 批量应用用户界面配置模板
java·前端·ui·sap·b1·无锡sap
axinawang2 小时前
XPath与lxml解析库
爬虫·python
Amos_Web2 小时前
Rspack 源码解析 (1) —— 架构总览:从 Node.js 到 Rust 的跨界之旅
前端·rust·node.js
qq_406176142 小时前
React 组件传参 & 路由跳转传参
前端·javascript·react.js
电商API&Tina2 小时前
唯品会数据采集API接口||电商API数据采集
java·javascript·数据库·python·sql·json
Csvn2 小时前
React 测试入门:Jest + Testing Library 完整指南
前端·react.js
悟空瞎说2 小时前
Flutter面试九阳神功第六层:Platform Channels/三棵树/Key/动画,大白话+实操代码(2026版)
前端
Oneslide2 小时前
手写签名组件实现原理
前端
zero15972 小时前
Python 8天极速入门笔记(大模型工程师专用):第三篇-列表与字典(Python核心数据结构,大模型必备)
开发语言·python·ai编程