Files
gc-plan/week7/教案.md
2026-04-29 23:45:17 +08:00

242 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Week 7前后端分离实战
**目标**:将 Vue 3 前端与 Spring Boot 后端完整对接,交付前后端分离的学生管理系统 v3。
**前置**:完成 Week 5Spring Boot 后端)和 Week 6Vue 3 前端基础)。
**本周产出**:前后端分离的完整 SPA 应用含登录注册、JWT 认证、CRUD、分页搜索、角色权限。
**启动方式**
```bash
# 1. 启动后端IDEA 中运行 Week7Application.java
# 2. 启动前端
cd week7/frontend
npm install # 首次运行
npm run dev # http://localhost:5173
```
---
## Day 1前后端分离架构设计
**知识点**
- 前后端分离 vs 单体架构:各自优劣
- 前端Vite 开发服务器5173→ 用户浏览器渲染
- 后端Spring Boot8080→ 只返回 JSON不渲染 HTML
- 通信方式HTTP + JSONJWT 无状态认证
- Vite proxy开发环境将 `/api` 请求代理到后端(解决跨域)
- 生产环境Nginx 反向代理,统一域名/端口
- CORSCross-Origin Resource SharingSpring Security 如何配置
**动手 → 理解**
1. 阅读 `vite.config.js``server.proxy` 配置,理解代理原理
2. 阅读 `SecurityConfig.java``corsConfigurationSource()` Bean
3. 在 DevTools Network 面板查看:`/api/students` 请求的远程地址是 5173 还是 8080
4. 对比 Week 5 的单体架构和 Week 7 的分离架构图
5. 把 Vite proxy 注释掉观察跨域错误CORS error
**核心文件**
- `frontend/vite.config.js``server.proxy`
- `backend/.../config/SecurityConfig.java` → CORS 配置
- `frontend/src/api/http.js` → Axios 实例
**思考题**前后端分离的核心优势是什么有什么代价首次加载速度、SEO
---
## Day 2登录注册页面 + JWT 对接
**知识点**
- 登录流程:表单输入 → Axios POST → 后端验证 → 返回 JWT → Pinia store 保存 → 跳转首页
- 注册流程:表单输入 → POST → 后端创建用户 → 返回 JWT → 自动登录
- Pinia Auth Store`token``username``role` 状态管理
- `localStorage`:持久化 Token页面刷新不丢失
- `<router-link>` vs 编程式导航 `router.push()`
- 导航守卫:`router.beforeEach()` 检查登录状态
- HTTP 拦截器:自动附加 `Authorization: Bearer <token>`
**动手 → 理解**
1. 打开 DevTools → Application → Local Storage观察 `wk7_token``wk7_username``wk7_role`
2. 在登录页输入错误密码,观察 Network 面板的 401 响应
3. 在 DevTools 中手动删除 Local Storage 的 token刷新页面观察跳转
4. 阅读 `router/index.js``beforeEach` 守卫逻辑
5. 注册一个新账号后,检查数据库中 users 表是否新增记录
**核心文件**
- `frontend/src/views/LoginView.vue` — 登录页面
- `frontend/src/views/RegisterView.vue` — 注册页面
- `frontend/src/stores/auth.js` — 认证状态管理
- `frontend/src/api/auth.js` — 认证 API
- `frontend/src/router/index.js` — 导航守卫
**思考题**:为什么 Token 存在 localStorage 而不是 Pinia store 中Pinia store 刷新后会丢失吗?
---
## Day 3CRUD 页面实现
**知识点**
- 列表渲染:`v-for` + Axios GET 请求
- 新增/编辑弹窗:`v-if` 控制显示,表单双向绑定 `v-model`
- 表单校验HTML5 原生校验 + 自定义 JS 校验
- 删除确认:`confirm()` + DELETE 请求
- 区分新增和编辑:根据是否传入 student 对象
- 角色权限:`v-if="auth.isAdmin"` 控制按钮显示
- 乐观更新 vs 悲观更新(操作后重新拉取数据)
**动手 → 理解**
1. 用 admin 登录,点击"新增",填写表单提交 → 观察 Network 面板 POST 请求
2. 点击"编辑",修改成绩后保存 → 观察 PUT 请求的请求体
3. 点击"删除" → 确认后观察 DELETE 请求,刷新页面确认数据消失
4. 用 user 登录,观察"新增/编辑/删除"按钮是否隐藏
5. 用 user 登录,在浏览器控制台执行 `fetch('/api/students', {method:'POST'})` 看 403
**核心文件**
- `frontend/src/views/StudentListView.vue` — 列表 + 表格
- `frontend/src/components/StudentForm.vue` — 表单弹窗props/emits
- `frontend/src/api/student.js` — CRUD API 调用
**思考题**:为什么不直接在表格行内编辑,而是用弹窗?各自适用什么场景?
---
## Day 4分页、搜索、排序
**知识点**
- 分页参数:`page`0-based`size`(每页数量)
- 前端分页 vs 后端分页:数据量决定策略
- 分页组件:首页/上一页/页码/下一页/末页 + 省略号逻辑
- 搜索防抖:`@keyup.enter` 触发搜索(避免每次按键都请求)
- 排序:后端 `ORDER BY` 实现MP LambdaQueryWrapper / JPA Sort
- URL 状态同步:搜索关键词和页码是否反映在 URL 参数中
**动手 → 理解**
1. 在搜索框输入"张",按回车 → 观察请求 URL 中的 `keyword` 参数
2. 点击分页组件的"下一页" → 观察 page 参数变化
3. 打开 `Pagination.vue`,理解省略号(...)的生成逻辑
4. 修改后端 `StudentMpService.list()` 中的排序字段为 `age` → 观察列表顺序变化
5. 在 Network 面板中对比:搜索前后 total 数量的变化
**核心文件**
- `frontend/src/components/Pagination.vue` — 分页组件
- `frontend/src/views/StudentListView.vue``search()` / `goPage()` 方法
- `backend/.../service/mp/StudentMpService.java` → LambdaQueryWrapper 排序
**思考题**:为什么页码从 0 开始Spring Data Pageable而不是从 1 开始?
---
## Day 5文件上传头像
**知识点**
- 前端:`<input type="file">` + `FormData`
- 后端:`MultipartFile` 接收文件
- Spring Boot 文件上传配置:`spring.servlet.multipart.max-file-size`
- 文件存储:本地目录 vs OSS对象存储
- 文件命名UUID 避免冲突
- 文件访问:静态资源映射 `addResourceHandlers()`
- 预览:上传后在前端显示缩略图
**动手 → 理解**
1. 在表单中增加 `<input type="file">` 字段
2.`FormData` 封装文件 + JSON 字段POST 到后端
3. 检查后端 `StudentController` 中的 `@RequestParam MultipartFile` 处理
4. 上传一个图片后,浏览器直接访问上传后的 URL
5. 尝试上传超大文件(>10MB观察 `MaxUploadSizeExceededException`
**核心文件**
- `frontend/src/components/StudentForm.vue` → 文件输入
- `backend/.../controller/StudentController.java` → MultipartFile 处理
- `backend/.../application.yml` → multipart 配置
**思考题**为什么不在数据库中存储文件二进制数据BLOB而是存储文件路径
---
## Day 6交互体验完善
**知识点**
- Loading 状态:数据加载中显示 spinner/骨架屏
- 错误状态:网络异常、后端报错时的用户提示
- 空状态:无数据时的友好占位
- 按钮 Loading提交时禁用按钮 + 显示"保存中..."
- Toast 消息:操作成功/失败的轻提示
- 乐观更新:先更新 UI 再发请求(失败时回滚)
- 防抖debounce和节流throttle
**动手 → 理解**
1. 强制停止后端,刷新前端页面 → 观察错误状态展示
2. 删除所有学生数据 → 观察空状态提示
3. 点击保存按钮时,快速双击 → 观察 loading 状态是否阻止了重复提交
4. 修改 `StudentListView.vue` 中的 loading 实现为骨架屏
5. 给搜索框加 300ms 的防抖
**核心文件**
- `frontend/src/views/StudentListView.vue` → loading / error / empty 三种状态
- `frontend/src/components/StudentForm.vue``formLoading` 按钮状态
**思考题**Loading、Empty、Error 三种状态分别应该在哪里处理(组件内 vs 全局)?
---
## Day 7前后端联调 & 部署概念
**知识点**
- 前后端联调:同时启动两个项目,确认所有接口正常
- Vite build生产环境构建 → 输出 `dist/` 目录
- Nginx 部署:反向代理将前后端统一到 80 端口
- Nginx 配置示例:`location /api { proxy_pass http://localhost:8080; }` + `location / { root dist/; }`
- 环境变量:`.env.development` vs `.env.production`
- Docker 部署概念:前端容器 + 后端容器 + Nginx 容器
- 部署检查清单数据库连接、Redis 连接、CORS 配置
**动手 → 理解**
1. 运行 `npm run build`,观察生成的 `dist/` 目录结构
2.`npx serve dist/` 预览生产构建
3. 用 Postman 测试后端所有 API 端点GET/POST/PUT/DELETE + Token
4. 画出完整的请求流程图:浏览器 → Nginx → 前端静态文件 / 后端 API
5. 阅读 Nginx 反向代理配置示例
**核心概念**
```
┌─────────────┐
│ 浏览器 │
│ localhost:80 │
└──────┬───────┘
┌──────┴───────┐
│ Nginx │
│ 端口 80 │
└──┬────────┬───┘
│ │
/ │ │ /api
│ │
┌─────┴──┐ ┌─────┴─────┐
│ dist/ │ │ Spring │
│ 静态 │ │ Boot:8080 │
└────────┘ └───────────┘
```
**思考题**Vite proxy 只用于开发环境,为什么生产环境要用 Nginx 而不是继续用 Vite proxy
---
## Week 7 总结
| 维度 | Week 5单体 | Week 6纯前端 | Week 7分离 |
|------|--------------|---------------|-------------|
| 前端框架 | 原生 HTML/JS | Vue 3 独立 | Vue 3 + 后端对接 |
| 页面路由 | 无 | Vue Router | Vue Router + 导航守卫 |
| 状态管理 | localStorage | Pinia 独立 | Pinia + API 同步 |
| 认证 | Login 页面display 切换) | 模拟登录 | JWT 真实认证 |
| 数据 | fetch 直连 | 无后端 | Axios + 拦截器 |
| 部署 | Spring Boot 单端口 | Vite dev | 前后端分端口 / Nginx |
**下一阶段Week 8 — 工程化能力**
- JUnit 5 + Mockito 单元测试
- Testcontainers 集成测试
- Knife4j API 文档
- Docker 容器化
- Git 工作流
- CI/CD 入门