news 2026/9/2 17:23:33

手把手教你用 Flask + Vue 3 打造一个功能齐全的全栈 Web 应用(PIWH 平台)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手把手教你用 Flask + Vue 3 打造一个功能齐全的全栈 Web 应用(PIWH 平台)
本文详细介绍一个基于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}(排序)参数。


八、安全设计(踩坑与心得)

这是我在项目中最花心思的部分,分享几个关键点:

  1. 密码一定要哈希存储,且登录时若发现旧明文数据要「自动升级」,平滑迁移历史数据。

  2. 验证码不能明文存库,我用哈希存储 + 失效机制(请求新码/重置成功时批量失效旧码)双保险,也修复了早期「验证码明文写日志」的高危漏洞。

  3. 登录/忘记密码接口必须限流,否则可被暴力枚举(这是我项目里标记为待优化的一点,登录接口当前还缺限流装饰器)。

  4. 文件上传要做多层校验:黑名单拦可执行文件、白名单限扩展名、MIME 校验防伪装、按用户目录隔离。

  5. 所有数据查询强制过滤f_user_id,这是多租户隔离最简单有效的做法。

完整的安全措施清单和潜在 Bug 分析,可以参考项目里的设计文档,这里不再赘述。


九、运行成功效果图

十、总结与展望

这个项目让我完整走了一遍「前后端分离」的开发流程,从架构设计、数据库建模、接口设计到安全防护,收获很大。当然它也有一些可以继续优化的地方,比如:

  • Token 目前是简单随机字符串,后续可迁移到JWT + Refresh Token

  • 限流器目前是内存存储,可引入Redis

  • 测试覆盖率偏低,可补充单元测试和集成测试;

  • 可引入DockerCI/CD提升工程化水平。

如果你也在学习 Flask 或 Vue,希望这篇文章和这个项目能给你一些启发。完整的代码结构和环境配置,可以参考项目的README.md

提示:本文所有示例代码中的数据库密码、邮箱账号等敏感信息均已用xxx代替,实际使用时请通过.env文件管理,切勿硬编码或提交到公开仓库。


如果这篇文章对你有帮助,欢迎点赞、收藏、关注,也欢迎在评论区交流你的想法~

有需要项目源码的,可以私我获取~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 17:20:18

SH79F1611驱动源码解析:8051内核MCU外设模块化开发实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 17:13:20

管理LVM

LVM逻辑卷管理LVM核心原理与架构LVM是Linux系统中一种分层式的磁盘管理机制,他在物理磁盘/分区与文件系统之间增加了一层逻辑抽象层,屏蔽了底层物理存储的硬件细节,让用户可以基于逻辑卷进行存储管理,而非直接操作物理磁盘。LVM的…

作者头像 李华
网站建设 2026/9/2 17:13:10

LLM Prompt Token效率检查:Tokensift Linter实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 17:12:26

(论文速读)Noise2Void:只用单张噪声图像训练去噪网络

论文题目:Noise2Void - Learning Denoising from Single Noisy Images(Noise2Void:从单张噪声图像中学习图像去噪)会议:CVPR 2019摘要:当前图像去噪领域主要由判别式深度学习方法主导,这些方法通…

作者头像 李华
网站建设 2026/9/2 17:12:14

Vue 3 + TypeScript 实战:从环境搭建到类型安全应用开发

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 17:12:07

本地嵌入+小模型:RSSMonster打造agentic RSS阅读器

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华