本文详细介绍一个基于Flask + Vue 3的全栈项目——PIWH 平台,涵盖项目背景、使用场景、技术选型、核心设计、使用方法和踩坑经验,并附完整代码结构和 API 设计,帮助你快速上手前后端分离开发。
一、写在前面:为什么要做这样一个项目
对于很多后端开发者来说,「会用 Flask 写接口」和「能独立搭起一个前后端分离的完整应用」之间,隔着一整条经验鸿沟:
接口怎么写才算规范、可维护?
权限认证、密码安全、文件上传这些「脏活累活」该怎么处理?
前端 Vue 和后端 Flask 之间怎么优雅地对接?
数据库的表结构、关联关系、迁移版本如何管理?
带着这些问题,我基于Flask 3 + Vue 3 + Element Plus + MySQL从零搭建了一个完整的全栈项目PIWH 平台。它把用户管理、待办事项、博客、记账、课程管理五个常见业务模块揉进了一个系统里,同时内置了 Token 认证、密码哈希、验证码、限流、文件上传校验等企业级能力。
这篇文章,就是我在这个项目中的完整复盘。希望能帮你少走一些弯路。
二、项目背景与应用场景
2.1 项目背景
PIWH 平台(项目代号test_flask_project-v1)最初是为了系统地练习「前后端分离」的开发范式而创建。在业务上,它像一个迷你版的「个人工作台」,把日常生活和工作中常见的几类需求整合在一起:
记一笔待办(Todo)
写一篇博客 / 笔记(Blog)
记一次账(Bookkeeping)
开一门课程、选一次课(Course)
2.2 典型使用场景
| 场景 | 对应模块 | 说明 |
|---|---|---|
| 个人任务管理 | 待办事项 | 记录每日待办,标记完成状态 |
| 知识沉淀 / 博客写作 | 博客系统 | 专栏分类、文章发布、读者评论 |
| 日常收支记账 | 记账管理 | 分类记账,按时间段统计收支 |
| 教学 / 培训管理 | 课程管理 | 课程创建、学生选课退课 |
| 账号与文件中心 | 用户 + 文件 | 注册登录、忘记密码、文件上传下载 |
换句话说,它既可以当作一个「个人效率工具箱」,也可以作为中小型业务系统(如课程平台、记账软件、博客站)的起步模板。
2.3 技术选型理由
Flask:轻量、灵活,配合 Flask-RESTX 能自动生成 Swagger 文档,适合快速搭建 RESTful API。
Vue 3 + Element Plus:生态成熟、组件丰富,Composition API 让逻辑复用更清晰。
MySQL + SQLAlchemy:关系型数据场景下最稳妥的组合,配合 Alembic 管理 schema 变更。
前后端分离:前端专注交互,后端专注业务与数据,职责清晰、可独立部署。
三、系统架构与核心设计
3.1 整体架构
┌──────────────────────────────────────────┐ │ 前端 (Vue 3) │ │ Element Plus → Pinia → Axios → API │ └───────────────────┬──────────────────────┘ │ HTTP (JSON) ┌───────────────────┴──────────────────────┐ │ 后端 (Flask) │ │ Services 层(API 视图) → Controls 层 │ │ (业务逻辑)→ Model 层(ORM) │ └───────────────────┬──────────────────────┘ │ ┌─────┴─────┐ │ MySQL │ └───────────┘
后端采用清晰的三层架构,各司其职:
| 层级 | 职责 |
|---|---|
Service 层(services/) | 注册路由、参数校验、调用控制层、序列化响应 |
Control 层(controls/) | 核心业务逻辑、权限校验、数据转换、邮件发送 |
Model 层(model/) | ORM 模型、表结构、关联关系 |
Common 层(common/) | 数据库基类、日志、限流、认证、分页工具 |
3.2 两个核心设计模式
BaseCtl 模式 —— 通用 CRUD
所有控制器继承BaseCtl,通过model_cls绑定模型,自动获得通用的增删改查能力,极大减少重复代码。
AdvResource 模式 —— 通用查询
所有 API 视图继承AdvResource,统一提供分页、过滤、搜索、排序能力,通过简单的查询参数即可完成复杂查询:
GET /blog/article/?page=1&limit=10&f_status=1&s_title=Flask&o_created_at=desc
四、数据库设计
项目共设计了 12 张表,核心关系如下:
User 1 ── N Token / Todo / File / Article / Comment / Expense / Record / Category User N ── N Course(通过 StudentCourse 中间表实现多对多) Category 1 ── N Article Article 1 ── N Comment Expense 1 ── N Record
几个值得注意的设计点:
多对多选课:通过
student_course中间表 +(user_id, course_id)联合唯一索引,防止重复选课。级联删除:所有一对多关系配置
cascade="all, delete-orphan",删除父记录自动清理子记录。验证码哈希存储:密码重置验证码使用 werkzeug 哈希后入库,防止数据库泄露时明文验证码被窃取。
五、核心功能与使用场景详解
5.1 用户模块(认证体系)
注册:用户名/邮箱唯一性校验、邮箱格式校验、密码强度校验(≥6 位含数字字母)、密码哈希后入库。
登录:密码校验(兼容旧明文数据,登录时自动升级为哈希)、Token 生成(
secrets.token_urlsafe)、记录 User-Agent 和 IP 用于设备绑定。忘记密码:邮箱发送 6 位验证码(3 分钟有效),验证通过后重置密码,并强制该用户所有 Token 失效。
文件上传:黑名单 + 白名单 + MIME 校验 + 用户目录隔离 + 同名自动重命名。
5.2 待办事项模块
每个 Todo 绑定到特定用户,同一用户名下name唯一,列表查询强制过滤当前用户数据,天然实现数据隔离。
5.3 博客模块
「专栏 → 文章 → 评论」三级结构,文章详情可带出评论列表(extend_fields=['comments']),删除时校验所有者身份,防止越权操作。
5.4 记账模块
收支分类 + 收支记录,统计接口使用数据库聚合查询:
SELECT COALESCE(SUM(income), 0), COALESCE(SUM(spend), 0) FROM record WHERE user_id = ? AND record_time BETWEEN ? AND ?
5.5 课程模块
典型的多对多关系,课程列表额外计算is_enrolled(当前用户是否已选)和studentCount(选课人数)。
六、使用步骤(手把手)
6.1 准备环境
Python 3.8+
Node.js 16+(推荐 18+)
MySQL 5.7+ / 8.x
6.2 配置环境变量
复制模板并填入真实值:
cp .env.example .env
.env关键配置(敏感信息请用你自己的值):
DB_USER=root DB_PASS=xxx DB_HOST=xxx DB_PORT=3306 DB_NAME=test MAIL_SERVER=smtp.qq.com MAIL_PORT=465 MAIL_USERNAME=xxx@qq.com MAIL_PASSWORD=xxx
6.3 初始化数据库
cd src pip install -r requirements.txt alembic upgrade head
6.4 安装前端依赖
cd frontend npm install
6.5 一键启动
回到项目根目录:
python start.py
浏览器访问http://localhost:5173,即可进入登录/注册页面。
后端 Swagger 文档地址:
http://localhost:5000/
七、API 设计一览
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /user/ | 注册用户 |
| POST | /user/token/ | 登录 |
| POST | /user/password-reset/request/ | 发送验证码 |
| POST | /user/password-reset/verify/ | 验证码重置密码 |
| GET/POST | /todo/ | Todo 列表/创建 |
| GET/POST | /blog/article/ | 文章列表/发布 |
| GET/POST | /blog/category/ | 专栏列表/创建 |
| GET/POST | /blog/comment/ | 评论列表/发表 |
| GET/POST | /bookkeeping/expense/ | 收支分类 |
| GET/POST | /bookkeeping/record/ | 收支记录 |
| POST | /bookkeeping/count/ | 收支统计 |
| GET/POST | /course/ | 课程列表/选课 |
所有 GET 列表接口支持统一的page/limit/f_{field}(精确过滤)/s_{field}(模糊搜索)/o_{field}(排序)参数。
八、安全设计(踩坑与心得)
这是我在项目中最花心思的部分,分享几个关键点:
密码一定要哈希存储,且登录时若发现旧明文数据要「自动升级」,平滑迁移历史数据。
验证码不能明文存库,我用哈希存储 + 失效机制(请求新码/重置成功时批量失效旧码)双保险,也修复了早期「验证码明文写日志」的高危漏洞。
登录/忘记密码接口必须限流,否则可被暴力枚举(这是我项目里标记为待优化的一点,登录接口当前还缺限流装饰器)。
文件上传要做多层校验:黑名单拦可执行文件、白名单限扩展名、MIME 校验防伪装、按用户目录隔离。
所有数据查询强制过滤
f_user_id,这是多租户隔离最简单有效的做法。
完整的安全措施清单和潜在 Bug 分析,可以参考项目里的设计文档,这里不再赘述。
九、运行成功效果图
十、总结与展望
这个项目让我完整走了一遍「前后端分离」的开发流程,从架构设计、数据库建模、接口设计到安全防护,收获很大。当然它也有一些可以继续优化的地方,比如:
Token 目前是简单随机字符串,后续可迁移到JWT + Refresh Token;
限流器目前是内存存储,可引入Redis;
测试覆盖率偏低,可补充单元测试和集成测试;
可引入Docker和CI/CD提升工程化水平。
如果你也在学习 Flask 或 Vue,希望这篇文章和这个项目能给你一些启发。完整的代码结构和环境配置,可以参考项目的README.md。
提示:本文所有示例代码中的数据库密码、邮箱账号等敏感信息均已用
xxx代替,实际使用时请通过.env文件管理,切勿硬编码或提交到公开仓库。
如果这篇文章对你有帮助,欢迎点赞、收藏、关注,也欢迎在评论区交流你的想法~
有需要项目源码的,可以私我获取~