跳到主要内容

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、前端和测试。
  • 增加“只看未完成”筛选。
  • 增加一个项目复盘文档,说明技术选型和下一步改进。