Skip to content

Repository files navigation

Java Todo API

基于 Spring Boot 的 Todo REST API,提供用户注册、登录认证、JWT 鉴权、RBAC 角色权限控制,以及 Todo 的创建、查询、修改、切换完成状态、删除、筛选等能力。

功能特性

  • RESTful Todo API
  • 用户注册和登录
  • JWT Token 鉴权
  • USER / ADMIN 角色权限控制
  • 管理员用户、Todo 和统计接口
  • 统一处理 401 未登录和 403 无权限响应
  • Todo 数据按用户隔离
  • Todo 软删除和恢复
  • completedAt / deletedAt 生命周期字段
  • Todo 操作日志
  • Todo 附件上传、列表、下载和删除
  • Todo 操作日志事件驱动异步写入
  • Todo 过期扫描定时任务
  • Todo 过期扫描任务状态查询
  • Service 层事务管理
  • Todo 详情和操作日志本地缓存
  • 支持 Redis profile 作为外部缓存
  • Redis 分布式锁、固定窗口限流和请求幂等
  • Kafka / RabbitMQ 消息队列适配和 Todo 操作日志消息化
  • Actuator 健康检查、应用信息和运行指标
  • Actuator liveness / readiness 探针
  • dev / prod 多环境配置示例
  • 使用 @ConfigurationProperties 绑定业务配置
  • 本地文件存储配置和附件元数据管理
  • 统一 API 响应结构
  • 业务错误码
  • 请求 / 响应 DTO 分层
  • 分页、排序、筛选列表查询
  • 全局异常处理
  • Bean Validation 参数校验
  • Spring Data JPA 数据持久化
  • Flyway 数据库迁移
  • 默认使用 H2 本地数据库
  • 支持 PostgreSQL profile
  • Java 21 多阶段 Dockerfile
  • Docker Compose 管理 Java 应用、PostgreSQL 和附件数据卷
  • Swagger / OpenAPI 接口文档
  • 带 requestId 的请求日志记录
  • 按功能拆分的 MockMvc 接口测试
  • JUnit 5 / Mockito Service 层单元测试
  • 查询索引、聚合统计和 EXPLAIN 性能测试
  • 数据库 CHECK 约束和 Todo 乐观锁
  • 并发更新冲突返回 HTTP 409
  • 数据库关系、迁移和索引设计文档
  • GitHub Actions CI 配置

技术栈

  • Java 21
  • Maven
  • Spring Boot 3.3.2
  • Spring Web
  • Spring Validation
  • Spring Security
  • Spring Data JPA
  • Spring Cache
  • Spring Data Redis
  • Spring Kafka
  • Spring AMQP / RabbitMQ
  • Spring Event / Async
  • Spring Scheduling
  • Spring Boot Actuator
  • Springdoc OpenAPI
  • Flyway
  • H2 Database
  • PostgreSQL Driver
  • Docker / Docker Compose(可选)
  • GitHub Actions(可选)
  • JUnit 5 / MockMvc

架构说明

HTTP 请求
  -> Security Filter
  -> Controller
  -> Service
  -> Event Publisher
  -> Event Listener
  -> Scheduled Job
  -> Repository
  -> Database

Actuator
  -> Health / Info / Metrics

Entity
  -> Mapper
  -> Response DTO

主要包结构:

com.zading.todoapi
├── config       工程配置,例如 OpenAPI 配置
│   └── properties 业务配置绑定对象
├── controller   HTTP 接口入口
├── dto          请求 / 响应对象
├── event        应用内部事件、事件发布器和事件监听器
├── exception    自定义异常和全局异常处理
├── job          定时任务和后台批处理入口
├── logging      请求日志过滤器
├── mapper       Entity 到 DTO 的转换
├── model        JPA Entity
├── repository   Spring Data JPA Repository
├── redis        Redis / 内存版锁、限流和幂等实现
├── messaging    消息模型、发布器、消费者和幂等处理器
├── security     JWT 和 Spring Security 配置
└── service      业务逻辑

项目结构

java-todo-api/
├── .dockerignore
├── .env.example
├── .github/
│   └── workflows/
│       └── ci.yml
├── docker-compose.yml
├── Dockerfile
├── pom.xml
├── README.md
├── docs/
│   ├── week-01-learning.md
│   ├── week-02-learning.md
│   ├── week-03-learning.md
│   ├── week-04-learning.md
│   ├── week-05-learning.md
│   ├── week-06-learning.md
│   ├── week-07-learning.md
│   ├── week-08-learning.md
│   ├── week-09-learning.md
│   ├── week-10-learning.md
│   ├── week-11-learning.md
│   ├── week-12-learning.md
│   ├── week-13-learning.md
│   ├── week-14-learning.md
│   ├── week-15-learning.md
│   ├── week-16-learning.md
│   ├── week-17-learning.md
│   ├── week-18-learning.md
│   ├── week-19-learning.md
│   ├── week-20-learning.md
│   ├── week-21-learning.md
│   ├── week-22-learning.md
│   ├── week-23-learning.md
│   ├── week-24-learning.md
│   ├── week-25-learning.md
│   └── week-26-learning.md
└── src/
    ├── main/
    │   ├── java/com/zading/todoapi/
    │   │   ├── TodoApiApplication.java
    │   │   ├── config/
    │   │   ├── controller/
    │   │   ├── dto/
    │   │   ├── event/
    │   │   ├── exception/
    │   │   ├── job/
    │   │   ├── logging/
    │   │   ├── mapper/
    │   │   ├── model/
    │   │   ├── repository/
    │   │   ├── redis/
    │   │   ├── security/
    │   │   └── service/
    │   └── resources/
    │       ├── application-dev.properties
    │       ├── application.properties
    │       ├── application-postgres.properties
    │       ├── application-prod.properties
    │       ├── application-kafka.properties
    │       ├── application-rabbitmq.properties
    │       ├── application-redis.properties
    │       └── db/migration/
    │           ├── V1__create_todos_table.sql
    │           ├── V2__add_priority_and_due_date_to_todos.sql
    │           ├── V3__create_users_and_link_todos.sql
    │           ├── V4__add_todo_lifecycle_fields.sql
    │           ├── V5__create_todo_action_logs_table.sql
│           ├── V6__create_todo_attachments_table.sql
│           ├── V7__add_user_role.sql
│           ├── V8__add_todo_query_indexes.sql
│           └── V9__add_data_constraints_and_todo_version.sql
    └── test/
        ├── java/com/zading/todoapi/
        │   ├── ApplicationSmokeTests.java
        │   ├── ActuatorTests.java
        │   ├── AuthApiTests.java
        │   ├── OpenApiTests.java
        │   ├── RbacApiTests.java
        │   ├── TodoQueryOptimizationTests.java
        │   ├── TodoDatabaseDesignTests.java
        │   ├── RedisProtectionTests.java
        │   ├── TodoAttachmentApiTests.java
        │   ├── TodoApiTests.java
        │   ├── service/
        │   │   ├── AdminServiceTest.java
        │   │   ├── AuthServiceTest.java
        │   │   ├── TodoAttachmentServiceTest.java
        │   │   └── TodoServiceTest.java
        │   └── support/
        └── resources/
            ├── mockito-extensions/
            └── application-test.properties

环境要求

  • JDK 21
  • Maven 3.9+

PostgreSQL 是可选依赖。默认 profile 使用 H2,因此本地没有安装 PostgreSQL 也可以直接运行。

Docker 也是可选工具。当前仓库提供了 docker-compose.yml,但不要求本机已经安装 Docker。

配置说明

默认配置

默认配置文件:

src/main/resources/application.properties

默认数据源:

spring.datasource.url=jdbc:h2:file:./data/todo-db-v2;MODE=PostgreSQL
spring.datasource.username=sa
spring.datasource.password=

数据库文件会生成在:

data/

data/ 目录已加入 Git 忽略规则。

PostgreSQL 配置

PostgreSQL 配置文件:

src/main/resources/application-postgres.properties

默认连接信息:

spring.datasource.url=${DB_URL:jdbc:postgresql://localhost:5432/java_todo_api}
spring.datasource.username=${DB_USERNAME:postgres}
spring.datasource.password=${DB_PASSWORD:}

创建数据库:

CREATE DATABASE java_todo_api;

使用 PostgreSQL profile 启动:

DB_USERNAME=postgres DB_PASSWORD=your_password mvn spring-boot:run -Dspring-boot.run.profiles=postgres

如果本机以后安装了 Docker,可以使用仓库内置的 Compose 配置启动 PostgreSQL:

cp .env.example .env
docker compose up -d postgres

然后启动 PostgreSQL profile:

DB_USERNAME=postgres DB_PASSWORD=postgres mvn spring-boot:run -Dspring-boot.run.profiles=postgres

Docker 容器化

第 24 周提供了多阶段 Dockerfile:构建阶段使用 Maven + JDK 21,运行阶段只使用 JRE 21 和最终 JAR。应用容器默认使用 prod profile,并通过 Compose 内部服务名 postgres 连接数据库。

先生成环境变量文件,并修改 JWT_SECRET

cp .env.example .env

检查 Compose 配置:

docker compose config

构建并启动 Java 应用和 PostgreSQL:

docker compose up -d --build

查看服务状态和应用日志:

docker compose ps
docker compose logs -f app

应用启动后可以访问:

http://localhost:8080/swagger-ui.html
http://localhost:8080/actuator/health

停止容器但保留数据库和附件数据:

docker compose down

如果明确需要删除数据卷,再执行:

docker compose down -v

注意:应用容器连接数据库时使用 postgres:5432,不能使用 localhost:5432。在容器内部,localhost 指向应用容器自己;postgres 才是 Compose 网络中的数据库服务名。附件保存到 app_uploads volume,容器删除后仍然可以保留。

dev 配置

开发环境配置文件:

src/main/resources/application-dev.properties

dev profile 面向本地开发:

保留 H2 Console
开启 SQL 日志
开启请求日志
业务包日志级别为 DEBUG

启动方式:

mvn spring-boot:run -Dspring-boot.run.profiles=dev

prod 配置

生产环境配置文件:

src/main/resources/application-prod.properties

prod profile 面向真实部署:

关闭 H2 Console
关闭 SQL 输出
敏感配置从环境变量读取
保留 Actuator 基础健康检查和探针

生产环境需要提供环境变量:

DB_URL=jdbc:postgresql://localhost:5432/java_todo_api
DB_USERNAME=postgres
DB_PASSWORD=your_password
JWT_SECRET=your-strong-secret
JWT_EXPIRATION_MINUTES=120

启动方式:

DB_URL=jdbc:postgresql://localhost:5432/java_todo_api \
DB_USERNAME=postgres \
DB_PASSWORD=your_password \
JWT_SECRET=your-strong-secret \
java -jar target/java-todo-api-1.0.0.jar --spring.profiles.active=prod

测试配置

测试配置文件:

src/test/resources/application-test.properties

测试环境使用 H2 内存数据库。

Redis 配置

Redis 配置文件:

src/main/resources/application-redis.properties

默认启动不连接 Redis,而是使用单 JVM 内存实现。启用 Redis profile 后,缓存、分布式锁、限流和幂等 Key 才会使用真实 Redis:

mvn spring-boot:run -Dspring-boot.run.profiles=redis

第 26 周的业务参数位于 app.redis.*

app.redis.lock-lease=5m
app.redis.idempotency-ttl=10m
app.redis.rate-limit-window=1m
app.redis.login-limit=5
app.redis.todo-create-limit=30

没有安装 Redis 时,不要启用 redis profile;默认配置已经可以运行、测试和学习接口流程。

JWT 配置

默认配置文件提供了学习环境可用的 JWT 配置:

app.jwt.secret=${JWT_SECRET:java-todo-api-learning-secret-change-me-at-least-32-chars}
app.jwt.expiration-minutes=${JWT_EXPIRATION_MINUTES:120}

生产环境不要使用默认密钥,应该通过环境变量设置:

JWT_SECRET=your-strong-secret
JWT_EXPIRATION_MINUTES=120

配置类绑定

项目使用 @ConfigurationProperties 把业务配置绑定成 Java 对象:

JwtProperties              app.jwt.*
RequestLoggingProperties   app.request-logging.*
TodoOverdueJobProperties   app.todo.overdue-job.*
FileStorageProperties      app.file-storage.*
RedisProtectionProperties  app.redis.*

这样业务代码不需要分散读取字符串配置 key,配置结构也更容易校验和维护。

文件存储配置

Todo 附件使用本地文件系统存储真实文件,数据库只保存附件元信息。

默认配置:

app.file-storage.root-location=uploads
app.file-storage.max-file-size-bytes=5242880

说明:

root-location       附件根目录
max-file-size-bytes 单个附件最大字节数,默认 5MB

uploads/ 已加入 .gitignore,不会提交到 Git 仓库。

测试环境使用:

app.file-storage.root-location=target/test-uploads

OpenAPI 配置

接口文档地址:

http://localhost:8080/swagger-ui.html

OpenAPI JSON 地址:

http://localhost:8080/v3/api-docs

Actuator 可观测性配置

项目提供 Spring Boot Actuator 基础可观测性端点:

GET /actuator/health   应用健康状态
GET /actuator/health/liveness   应用进程是否存活
GET /actuator/health/readiness  应用是否准备好接收请求
GET /actuator/info     应用基础信息
GET /actuator/metrics  JVM、HTTP、进程等运行指标列表

默认只开放 healthinfometrics 三类端点:

management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=never
management.endpoint.health.probes.enabled=true
management.info.env.enabled=true

默认环境不强制检查 Redis:

management.health.redis.enabled=false

这是为了保证本机没有安装 Redis 时,应用仍然可以正常启动,/actuator/health 也不会因为 Redis 未连接而返回 DOWN

启用 redis profile 时,会重新打开 Redis 健康检查:

management.health.redis.enabled=true

请求日志配置

默认开启请求日志:

app.request-logging.enabled=true
app.request-logging.request-id-header=X-Request-Id

日志会记录:

requestId=abc123 HTTP GET /api/todos -> 200 (12 ms)

如果请求头中带了 X-Request-Id,系统会复用它;如果没有携带,系统会自动生成一个 UUID,并通过响应头返回。

缓存配置

默认使用 Spring Boot Simple Cache:

spring.cache.type=simple

这是本地内存缓存,不需要安装 Redis。当前缓存内容:

todoDetail  Todo 详情缓存
todoLogs    Todo 操作日志缓存

写操作会清理相关缓存,避免返回旧数据:

update / toggle / delete / restore
  -> 清理 todoDetail
  -> 清理 todoLogs

如果本地或服务器已经有 Redis,可以启用 redis profile,把缓存底层从本地内存切换成 Redis:

mvn spring-boot:run -Dspring-boot.run.profiles=redis

Redis 连接配置文件:

src/main/resources/application-redis.properties

默认连接信息:

spring.cache.type=redis
spring.data.redis.host=${REDIS_HOST:localhost}
spring.data.redis.port=${REDIS_PORT:6379}
spring.data.redis.password=${REDIS_PASSWORD:}
spring.data.redis.timeout=2s

当前 Redis 缓存 TTL:

todoDetail  10 分钟
todoLogs     5 分钟
默认缓存     10 分钟

如果没有安装 Redis,不要启用 redis profile,直接使用默认启动方式即可。

异步事件配置

项目使用 Spring Event 解耦 Todo 主业务和操作日志写入:

TodoService
  -> 发布 TodoActionLogEvent
  -> 事务提交后 TodoActionLogEventListener 接收事件
  -> 使用 todoTaskExecutor 异步写入 TodoActionLog

异步线程池配置文件:

src/main/java/com/zading/todoapi/config/AsyncConfig.java

当前线程池参数:

核心线程数:2
最大线程数:4
队列容量:100
线程名前缀:todo-async-

定时任务配置

项目使用 Spring Scheduling 定时扫描过期 Todo:

每天 09:00
  -> 扫描 dueDate 早于今天、未完成、未删除的 Todo
  -> 如果还没有 OVERDUE 日志,则发布 TodoActionLogEvent
  -> 异步写入 Todo 操作日志

定时任务入口:

src/main/java/com/zading/todoapi/job/TodoOverdueJob.java

默认配置:

app.todo.overdue-job.enabled=true
app.todo.overdue-job.cron=0 0 9 * * *
app.todo.overdue-job.zone=Asia/Shanghai
app.todo.overdue-job.page-size=50

测试环境会关闭定时任务:

app.todo.overdue-job.enabled=false

启用 Redis profile 后,过期扫描会先获取 lock:todo-overdue-job。如果其他应用实例已经持有这把锁,本实例会跳过本轮扫描。

任务最近一次执行状态可以通过内部接口查询:

GET /api/internal/jobs/todo-overdue
Authorization: Bearer <token>

响应数据字段:

字段 说明
jobName 任务名称
lastRunDate 最近一次扫描对应的业务日期
lastRunAt 最近一次实际执行时间
lastSuccess 最近一次是否执行成功
lastProcessedCount 最近一次处理的 Todo 数量
lastDurationMs 最近一次耗时,单位毫秒
lastErrorMessage 最近一次失败原因,成功时为 null

数据库迁移

Flyway 迁移脚本目录:

src/main/resources/db/migration/

当前迁移脚本:

V1__create_todos_table.sql
V2__add_priority_and_due_date_to_todos.sql
V3__create_users_and_link_todos.sql
V4__add_todo_lifecycle_fields.sql
V5__create_todo_action_logs_table.sql
V6__create_todo_attachments_table.sql
V7__add_user_role.sql
V8__add_todo_query_indexes.sql
V9__add_data_constraints_and_todo_version.sql

JPA 不负责自动修改表结构:

spring.jpa.hibernate.ddl-auto=validate

数据库表结构由 Flyway 管理,JPA 只校验 Entity 模型和数据库表结构是否匹配。

第 25 周的数据库设计说明位于:

docs/database-design.md

文档记录了表关系、数据库约束、索引、事务边界和 Todo 乐观锁设计。

启动项目

cd /Users/zading/Documents/Java/java-todo-api
mvn spring-boot:run

健康检查:

curl http://localhost:8080/hello

预期响应:

Hello Spring Boot

接口文档:

http://localhost:8080/swagger-ui.html

运行测试

mvn test

测试结构:

src/test/java/com/zading/todoapi/
├── ActuatorTests.java           Actuator 健康检查 / 信息 / 指标测试
├── ApplicationSmokeTests.java   应用冒烟测试
├── AuthApiTests.java            注册 / 登录接口测试
├── OpenApiTests.java            OpenAPI 文档测试
├── RbacApiTests.java            角色和管理员接口测试
├── TodoQueryOptimizationTests.java 索引、聚合查询和 EXPLAIN 测试
├── TodoDatabaseDesignTests.java 数据库迁移、约束和乐观锁测试
├── RedisProtectionTests.java    内存锁、限流和幂等测试
├── TodoAttachmentApiTests.java  Todo 附件上传 / 下载接口测试
├── TodoApiTests.java            Todo 业务接口测试
├── service/
│   ├── AdminServiceTest.java    AdminService 单元测试
│   ├── AuthServiceTest.java     AuthService 单元测试
│   ├── TodoAttachmentServiceTest.java
│   └── TodoServiceTest.java     TodoService 单元测试
└── support/
    ├── AbstractApiTest.java     测试公共配置和数据清理
    ├── AuthTestClient.java      认证接口测试辅助类
    └── TodoTestClient.java      Todo 接口测试辅助类

测试覆盖:

  • 健康检查接口
  • 用户注册
  • 用户登录
  • 新注册用户默认 USER 角色
  • 重复用户名注册失败
  • 错误密码登录失败
  • 未登录访问 Todo 返回 401
  • 未登录访问管理员接口返回 401
  • 普通用户访问管理员接口返回 403
  • 管理员查询用户、Todo 和统计数据
  • 创建 Todo
  • 查询 Todo 列表
  • 修改 Todo
  • 切换完成状态
  • 删除 Todo
  • 恢复软删除 Todo
  • 查询 Todo 操作日志
  • 上传 Todo 附件
  • 查询 Todo 附件列表
  • 下载 Todo 附件
  • 删除 Todo 附件
  • 空附件上传失败
  • Todo 附件用户隔离
  • Todo 操作日志事件驱动异步写入
  • Todo 过期扫描定时任务
  • Todo 过期扫描任务状态查询
  • Todo 详情缓存和缓存失效
  • Todo 操作日志缓存和缓存失效
  • Redis profile 配置和 TTL 设置
  • 按完成状态筛选
  • 按标题关键词搜索
  • 分页和排序
  • priority / dueDate 字段
  • completedAt / deletedAt 生命周期字段
  • 软删除后默认查询不可见
  • Todo 操作日志写入和用户隔离
  • Todo 数据按用户隔离
  • OpenAPI 文档可访问
  • Actuator health / info / metrics 可访问
  • Actuator liveness / readiness 可访问
  • 请求日志 requestId 响应头
  • 参数校验错误响应
  • 统一成功 / 错误响应结构
  • 业务错误码
  • 资源不存在错误响应
  • Service 层正常流程、异常和用户隔离单元测试
  • JWT 角色传递和密码校验单元测试
  • 管理员统计和软删除查询单元测试
  • 附件大小、路径安全和文件生命周期单元测试
  • Todo 查询索引、聚合统计和执行计划测试
  • Redis 分布式锁、限流和幂等流程测试

Service 单元测试可以单独运行:

mvn -q -Dtest=TodoServiceTest,AuthServiceTest,AdminServiceTest,TodoAttachmentServiceTest test

查询优化测试可以单独运行:

mvn -q -Dtest=TodoQueryOptimizationTests test

CI

仓库提供 GitHub Actions 配置:

.github/workflows/ci.yml

当前 CI 会在 main 分支的 push 和 pull request 上执行:

mvn test
mvn package -DskipTests

CI 配置不会在本地自动执行;只有代码推送到 GitHub 并启用 Actions 后才会运行。

构建

mvn package

运行打包后的应用:

java -jar target/java-todo-api-1.0.0.jar

使用 PostgreSQL profile 运行打包后的应用:

DB_USERNAME=postgres DB_PASSWORD=your_password \
java -jar target/java-todo-api-1.0.0.jar --spring.profiles.active=postgres

使用 dev profile 运行:

java -jar target/java-todo-api-1.0.0.jar --spring.profiles.active=dev

使用 prod profile 运行:

DB_URL=jdbc:postgresql://localhost:5432/java_todo_api \
DB_USERNAME=postgres \
DB_PASSWORD=your_password \
JWT_SECRET=your-strong-secret \
java -jar target/java-todo-api-1.0.0.jar --spring.profiles.active=prod

API 文档

健康检查

GET /hello

响应:

Hello Spring Boot

用户注册

POST /api/auth/register
Content-Type: application/json

请求体:

{
  "username": "zading",
  "password": "123456"
}

响应:

{
  "success": true,
  "code": "CREATED",
  "message": "创建成功",
  "data": {
    "id": 1,
    "username": "zading",
    "role": "USER",
    "createdAt": "2026-08-12T10:00:00.123456"
  },
  "path": null
}

用户登录

POST /api/auth/login
Content-Type: application/json

请求体:

{
  "username": "zading",
  "password": "123456"
}

响应:

{
  "success": true,
  "code": "OK",
  "message": "成功",
  "data": {
    "token": "xxxxx.yyyyy.zzzzz",
    "tokenType": "Bearer"
  },
  "path": null
}

管理员接口

管理员接口统一位于 /api/admin/**,只有 ADMIN 角色可以访问。

GET /api/admin/users?page=0&size=10&sort=id,asc
Authorization: Bearer <admin-token>
GET /api/admin/todos?page=0&size=10&sort=id,asc
Authorization: Bearer <admin-token>

默认不返回软删除 Todo;管理员可以通过 includeDeleted=true 查看:

GET /api/admin/todos?includeDeleted=true
Authorization: Bearer <admin-token>
GET /api/admin/statistics
Authorization: Bearer <admin-token>

普通注册用户默认是 USER,公开注册接口不会接收 role 字段。学习环境可以先注册用户,再执行:

UPDATE users SET role = 'ADMIN' WHERE username = 'zading';

修改角色后需要重新登录,获得包含新角色的 JWT。

未登录请求返回 401 UNAUTHORIZED,普通用户请求管理员接口返回 403 FORBIDDEN

统一响应结构

/hello 健康检查接口外,业务 API 统一使用下面的响应结构:

{
  "success": true,
  "code": "OK",
  "message": "成功",
  "data": {},
  "path": null
}

字段说明:

字段 类型 说明
success boolean 请求是否成功
code string 业务状态码,例如 OKTODO_NOT_FOUND
message string 给前端展示或调试使用的消息
data object/null 真正的业务数据
path string/null 出错时的请求路径

前端接入时,业务数据统一从 data 字段中读取。

认证说明

/hello/api/auth/register/api/auth/login/actuator/health/**/actuator/info/actuator/metrics/**/h2-console/**/v3/api-docs/**/swagger-ui/** 外,其他接口都需要登录。/api/admin/** 还需要 ADMIN 角色。

访问 Todo API 时需要携带:

Authorization: Bearer <token>

Actuator 接口

GET /actuator/health
GET /actuator/health/liveness
GET /actuator/health/readiness
GET /actuator/info
GET /actuator/metrics
GET /actuator/metrics/jvm.memory.used

Actuator 端点用于观察应用运行状态,不返回具体业务数据。

查询 Todo 过期扫描任务状态

GET /api/internal/jobs/todo-overdue
Authorization: Bearer <token>

响应:

{
  "success": true,
  "code": "OK",
  "message": "成功",
  "data": {
    "jobName": "todo-overdue",
    "lastRunDate": "2026-08-21",
    "lastRunAt": "2026-08-21T09:00:00.123456",
    "lastSuccess": true,
    "lastProcessedCount": 3,
    "lastDurationMs": 18,
    "lastErrorMessage": null
  },
  "path": null
}

上传 Todo 附件

POST /api/todos/{todoId}/attachments
Authorization: Bearer <token>
Content-Type: multipart/form-data

表单字段:

字段 类型 必填 说明
file file 要上传的附件文件

响应:

{
  "success": true,
  "code": "CREATED",
  "message": "创建成功",
  "data": {
    "id": 1,
    "todoId": 10,
    "originalFilename": "note.txt",
    "contentType": "text/plain",
    "fileSize": 16,
    "createdAt": "2026-08-21T14:30:00.123456"
  },
  "path": null
}

查询 Todo 附件列表

GET /api/todos/{todoId}/attachments
Authorization: Bearer <token>

响应:

{
  "success": true,
  "code": "OK",
  "message": "成功",
  "data": [
    {
      "id": 1,
      "todoId": 10,
      "originalFilename": "note.txt",
      "contentType": "text/plain",
      "fileSize": 16,
      "createdAt": "2026-08-21T14:30:00.123456"
    }
  ],
  "path": null
}

下载 Todo 附件

GET /api/todos/{todoId}/attachments/{attachmentId}/download
Authorization: Bearer <token>

下载接口直接返回文件流,并设置:

Content-Type: <文件类型>
Content-Disposition: attachment

删除 Todo 附件

DELETE /api/todos/{todoId}/attachments/{attachmentId}
Authorization: Bearer <token>

响应:

{
  "success": true,
  "code": "OK",
  "message": "删除附件成功",
  "data": null,
  "path": null
}

查询 Todo 列表

GET /api/todos
Authorization: Bearer <token>

Query 参数:

参数名 类型 必填 说明
completed boolean 按完成状态筛选
keyword string 按标题关键词搜索
page number 页码,从 0 开始,默认 0
size number 每页数量,默认 10,最大 100
sort string 排序规则,格式为 字段,方向,默认 id,asc

示例:

GET /api/todos
GET /api/todos?page=0&size=10
GET /api/todos?page=0&size=10&completed=true
GET /api/todos?page=0&size=10&keyword=java
GET /api/todos?page=0&size=10&completed=false&keyword=java&sort=createdAt,desc

响应:

{
  "success": true,
  "code": "OK",
  "message": "成功",
  "data": {
    "items": [
      {
        "id": 1,
        "title": "实现 Todo API",
        "completed": false,
        "deleted": false,
        "priority": "HIGH",
        "dueDate": "2026-09-20",
        "completedAt": null,
        "deletedAt": null,
        "createdAt": "2026-08-12T10:00:00.123456",
        "updatedAt": "2026-08-12T10:00:00.123456"
      }
    ],
    "page": 0,
    "size": 10,
    "totalElements": 1,
    "totalPages": 1,
    "first": true,
    "last": true
  },
  "path": null
}

查询单个 Todo

GET /api/todos/{id}
Authorization: Bearer <token>

示例:

curl http://localhost:8080/api/todos/1 \
  -H "Authorization: Bearer <token>"

查询 Todo 操作日志

GET /api/todos/{id}/logs
Authorization: Bearer <token>

示例:

curl http://localhost:8080/api/todos/1/logs \
  -H "Authorization: Bearer <token>"

响应:

{
  "success": true,
  "code": "OK",
  "message": "成功",
  "data": [
    {
      "id": 1,
      "action": "CREATED",
      "description": "创建 Todo",
      "createdAt": "2026-08-17T10:00:00.123456"
    },
    {
      "id": 2,
      "action": "COMPLETED",
      "description": "完成 Todo",
      "createdAt": "2026-08-17T10:10:00.123456"
    }
  ],
  "path": null
}

当前记录的操作类型:

CREATED      创建 Todo
UPDATED      修改 Todo
COMPLETED    完成 Todo
UNCOMPLETED  取消完成 Todo
DELETED      删除 Todo
RESTORED     恢复 Todo

创建 Todo

POST /api/todos
Content-Type: application/json
Authorization: Bearer <token>

请求体:

{
  "title": "实现 Todo API",
  "priority": "HIGH",
  "dueDate": "2026-09-20"
}

示例:

curl -X POST http://localhost:8080/api/todos \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token>" \
  -d '{"title":"实现 Todo API","priority":"HIGH","dueDate":"2026-09-20"}'

成功状态码:

201 Created

修改 Todo

PATCH /api/todos/{id}
Content-Type: application/json
Authorization: Bearer <token>

请求体:

{
  "title": "更新 API 文档",
  "completed": true,
  "priority": "LOW",
  "dueDate": "2026-09-25"
}

两个字段都可以单独传。

示例:

curl -X PATCH http://localhost:8080/api/todos/1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token>" \
  -d '{"title":"更新 API 文档","completed":true,"priority":"LOW","dueDate":"2026-09-25"}'

切换完成状态

PATCH /api/todos/{id}/toggle
Authorization: Bearer <token>

示例:

curl -X PATCH http://localhost:8080/api/todos/1/toggle \
  -H "Authorization: Bearer <token>"

完成状态规则:

未完成 -> 完成:completed = true,completedAt 写入当前时间
完成 -> 未完成:completed = false,completedAt 清空为 null

删除 Todo

DELETE /api/todos/{id}
Authorization: Bearer <token>

示例:

curl -X DELETE http://localhost:8080/api/todos/1 \
  -H "Authorization: Bearer <token>"

成功状态码:

200 OK

响应:

{
  "success": true,
  "code": "OK",
  "message": "删除成功",
  "data": null,
  "path": null
}

删除行为说明:

当前删除是软删除:数据库记录不会物理删除,而是设置 deleted = true,并写入 deletedAt。
普通查询默认只返回 deleted = false 的 Todo。

恢复 Todo

PATCH /api/todos/{id}/restore
Authorization: Bearer <token>

示例:

curl -X PATCH http://localhost:8080/api/todos/1/restore \
  -H "Authorization: Bearer <token>"

响应:

{
  "success": true,
  "code": "OK",
  "message": "恢复成功",
  "data": {
    "id": 1,
    "title": "实现 Todo API",
    "completed": false,
    "deleted": false,
    "priority": "HIGH",
    "dueDate": "2026-09-20",
    "completedAt": null,
    "deletedAt": null,
    "createdAt": "2026-08-12T10:00:00.123456",
    "updatedAt": "2026-08-12T10:05:00.123456"
  },
  "path": null
}

错误响应

参数校验错误示例:

{
  "success": false,
  "code": "VALIDATION_FAILED",
  "message": "title: 任务标题不能为空",
  "data": null,
  "path": "/api/todos"
}

资源不存在示例:

{
  "success": false,
  "code": "TODO_NOT_FOUND",
  "message": "Todo 不存在,id = 999",
  "data": null,
  "path": "/api/todos/999"
}

未登录示例:

{
  "success": false,
  "code": "UNAUTHORIZED",
  "message": "请先登录",
  "data": null,
  "path": "/api/todos"
}

文档

学习文档位于 docs/

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages