项目实训博客第一篇
本周完成了美食知识库模块的基础开发,包含菜系百科、食材大全等5个子模块及全局搜索功能。技术架构采用FastAPI+MySQL+Flutter,设计了5张核心数据表并使用JSON字段实现灵活存储。后端实现了8个API接口,前端通过TabController管理多标签页并行加载。开发中解决了数据类型转换、布局溢出等问题,并优化了搜索功能的防抖处理。后续将继续完善内容。
一、本周工作概述
本周是教学日历的第6周,按照实施计划,我在6周结束前完成了菜单翻译官APP中美食知识库模块的基础功能开发。该模块是APP四大页面(首页、知识库、工具集、我的)之一,基础功能包括:菜系百科、食材大全、烹饪方法、饮食文化、名人美食五大子模块,以及全局搜索功能。目前已完成的是基础版,后续将继续完善美食知识库内容。
本周完成的具体工作:
-
后端API接口设计与实现(8个主要接口)
-
数据库表结构设计(5张核心表)
-
前端Flutter页面开发(5个Tab页面 + 5个详情页面)
-
前后端联调与数据类型问题解决
二、技术选型与架构设计
2.1 技术栈
| 层次 | 技术 | 说明 |
|---|---|---|
| 后端框架 | FastAPI | 高性能异步框架,自动生成API文档 |
| 数据库 | MySQL + SQLAlchemy | 关系型数据库 + ORM |
| 前端 | Flutter Web | 跨平台开发,一套代码多端运行 |
| AI集成 | 通义千问(后续接入) | 用于菜品文化知识生成 |
三、数据库设计
知识库模块共设计了5张核心数据表:
| 表名 | 说明 | 主要字段 |
|---|---|---|
| cuisines | 菜系百科 | cuisine_id, name, country, characteristics, famous_dishes |
| ingredients | 食材大全 | ingredient_id, name, category, nutrition, common_allergen |
| cooking_methods | 烹饪方法 | method_id, name, category, steps, tips |
| food_culture | 饮食文化 | culture_id, title, category, country, content |
| celebrity_foods | 名人美食 | celebrity_id, name, era, favorite_foods, famous_quotes |
设计要点:
-
使用JSON字段存储列表数据(如
famous_dishes、steps),便于扩展, 因为每道菜的“代表菜品”数量不固定,用JSON可以灵活存储数组,避免创建关联表增加复杂度。 -
添加
status字段支持软删除 -
添加
sort_order字段控制展示顺序
四、后端API实现
以菜系百科接口为例:
接口定义: GET /knowledge/cuisines
返回示例:
{
"code": 200,
"data": [
{
"cuisine_id": "chinese_sichuan",
"name": "川菜",
"country": "中国",
"characteristics": "麻辣鲜香、味型丰富",
"famous_dishes": ["麻婆豆腐", "宫保鸡丁", "回锅肉"]
}
]
}
核心代码逻辑:
-
从MySQL查询status=1的菜系数据
-
按sort_order排序
-
解析JSON字段(famous_dishes、cooking_methods)
-
返回统一格式的响应
完成的API列表:
-
GET /knowledge/cuisines- 菜系列表 -
GET /knowledge/cuisines/{id}- 菜系详情 -
GET /knowledge/ingredients- 食材列表 -
GET /knowledge/ingredients/{id}- 食材详情 -
GET /knowledge/cooking-methods- 烹饪方法列表 -
GET /knowledge/cooking-methods/{id}- 烹饪方法详情 -
GET /knowledge/culture- 饮食文化列表 -
GET /knowledge/culture/{id}- 饮食文化详情 -
GET /knowledge/celebrities- 名人列表 -
GET /knowledge/celebrities/{id}- 名人详情 -
GET /knowledge/search?keyword=xxx- 全局搜索
五、前端页面实现
5.1 页面结构与状态管理
知识库主页包含5个Tab,每个Tab独立加载数据。我使用TabController管理标签切换,并用多个List<dynamic>分别存储各模块数据。加载时并行请求5个API,减少用户等待时间。
Future<void> _loadAllData() async {
await Future.wait([
_loadCuisines(),
_loadIngredients(),
_loadCookingMethods(),
_loadCultures(),
_loadCelebrities(),
]);
}
5.2 搜索功能的实现
搜索框实时响应用户输入,调用/knowledge/search接口。为了减少请求频率,我添加了防抖(debounce),用户停止输入300ms后再发起请求。
遇到的困难:搜索结果中的id字段在不同类型中含义不同(菜系用cuisine_id,食材用ingredient_id)。我统一使用item['id'],但后端返回的字段名是id(搜索接口特意做了别名处理),保证了前端逻辑简单。
5.3 布局溢出的问题
AppBar中同时放置了搜索框和TabBar,导致高度不够,出现RenderFlex overflowed警告。解决方案:设置toolbarHeight: 120,并将Column的mainAxisSize设为min,让子组件自适应高度。
这提醒我:Flutter的布局约束是严格的,需要明确给父组件足够的空间,否则会溢出。
六、成果展示与反思
6.1 完成的功能
-
5个知识库子模块的列表与详情页
-
全局搜索(支持菜系、食材、文化、名人)
-
前后端完整联调,数据正确展示
-
响应式布局,在Chrome上均表现良好
6.2 技术成长
-
深入理解了前后端数据契约的重要性,学会了使用类型检查和序列化工具避免运行时错误。
-
掌握了FastAPI + SQLAlchemy的开发流程,包括异步查询、JSON字段处理。
-
熟练了Flutter的布局调试,尤其是AppBar和TabBar的组合使用。
-
学会了用Chrome DevTools调试网络请求和查看前端错误堆栈。
6.3 后续改进方向
-
当前知识库是“静态”的,后续将使其动态化、智能化
更多推荐
所有评论(0)