11.2 全栈 Todo 项目切片
项目实战的第一步不是一次写完整系统,而是做一个“纵向切片”:从需求到数据库、API、前端和测试打通一个最小业务闭环。
学习目标
- 能把业务需求拆成可交付的最小切片。
- 能设计后端实体、DTO、API 和数据库迁移。
- 能用 Blazor 或 React + TypeScript 调用 API。
- 能为核心路径补充基本测试。
- 能把这段功能写成简历和面试中可讲的项目经历。
应用场景
- 新项目启动时验证架构和技术栈。
- 面试项目中展示全栈闭环能力。
- 团队开发中按功能切片交付,而不是按层长期分支。
业务需求
第一版只做三件事:
| 功能 | 验收标准 |
|---|---|
| 创建任务 | 输入标题后保存到数据库,标题不能为空 |
| 查看列表 | 按创建时间倒序展示任务 |
| 完成任务 | 点击完成后状态变为已完成,重复完成不报错 |
技术切片
后端接口契约
| 方法 | 路径 | 用途 | 成功响应 |
|---|---|---|---|
GET | /todos | 获取任务列表 | 200 OK + 数组 |
POST | /todos | 创建任务 | 201 Created + 新任务 |
PUT | /todos/{id}/complete | 完成任务 | 204 No Content |
app.MapGet("/todos", async (TodoService service, CancellationToken cancellationToken) =>
Results.Ok(await service.GetAllAsync(cancellationToken)));
app.MapPost("/todos", async (
CreateTodoRequest request,
TodoService service,
CancellationToken cancellationToken) =>
{
if (string.IsNullOrWhiteSpace(request.Title))
{
return Results.BadRequest(new {message = "标题不能为空"});
}
var todo = await service.CreateAsync(request, cancellationToken);
return Results.Created($"/todos/{todo.Id}", todo);
});
app.MapPut("/todos/{id:int}/complete", async (
int id,
TodoService service,
CancellationToken cancellationToken) =>
{
var completed = await service.CompleteAsync(id, cancellationToken);
return completed ? Results.NoContent() : Results.NotFound();
});
前端页面职责
无论选择 Blazor 还是 React + TypeScript,页面都应该覆盖这些状态:
- 初始加载:展示加载状态。
- 加载失败:展示错误提示,允许重试。
- 空列表:展示空状态和创建入口。
- 创建中:禁用提交按钮,避免重复提交。
- 完成任务:局部更新列表状态。
测试清单
- 创建任务:标题有效时返回 201,并能在列表中看到。
- 创建任务:标题为空时返回 400。
- 完成任务:存在的任务返回 204,并更新状态。
- 完成任务:不存在的任务返回 404。
- 列表排序:新任务排在旧任务前面。
重点难点
- 不要先做庞大目录结构;先让一个功能端到端跑通。
- API 契约要先稳定,否则前端会不断跟着字段变化返工。
- 数据库迁移、DTO 和前端类型要一起更新。
- 项目演示时要讲清“为什么这样拆分”,而不只是展示代码。
简历表达示例
设计并实现 Todo 任务管理系统的首个全栈功能切片,使用 ASP.NET Core Minimal API、EF Core 和 React/Blazor 完成任务创建、查询和状态更新,补充核心 API 集成测试,并通过统一 DTO 契约降低前后端联调成本。
练习
- 为任务增加优先级字段,并同步更新数据库、API、前端和测试。
- 增加“只看未完成”筛选。
- 增加一个项目复盘文档,说明技术选型和下一步改进。