生成代码工程

This commit is contained in:
root 2026-04-24 17:13:51 +08:00
parent 4bc29c9a7d
commit bd56f7a6d1
7 changed files with 4290 additions and 5482 deletions

View File

@ -1,61 +1,47 @@
# Demo Spring Boot Project
# 单体示例工程
## 项目说明
一个基于 FastAPI 的简单待办事项Todo管理服务使用内存假数据存储。
本项目是一个使用 **Spring Boot 3.x + Java 17** 构建的单体后端工程,集成了 **Knife4j (Swagger/OpenAPI)** 用于接口文档展示。
## 功能
### 技术栈
- 获取所有待办事项列表
- 根据 ID 获取单个待办事项
- 创建新的待办事项
- 更新待办事项
- 删除待办事项
- Java 17
- Spring Boot 3.2.4
- Knife4j 4.5.0 (OpenAPI 3)
- Maven
- Lombok
### 业务说明
- 当前所有业务数据使用**内存假数据**,未接入任何数据库或外部基础设施。
- 已预留 Repository 接口层扩展点,后续可对接数据库实现。
### 启动方式
## 安装依赖
```bash
# 编译
mvn clean package
# 运行
mvn spring-boot:run
# 或直接运行生成的 jar
java -jar target/demo-0.0.1-SNAPSHOT.jar
cd codegen-runs/codegen_a2cef5070965479b93c5b3c07d4c8216
pip install -r requirements.txt
```
### 接口文档访问
## 启动服务
启动后,打开浏览器访问:
- **Knife4j UI**: http://localhost:8080/doc.html
- **Swagger UI**: http://localhost:8080/swagger-ui/index.html
- **OpenAPI JSON**: http://localhost:8080/v3/api-docs
### 项目结构
```
src/main/java/com/example/demo/
├── DemoApplication.java # 启动类
├── config/
│ └── OpenApiConfig.java # Knife4j/Swagger 配置
├── controller/
│ ├── HealthController.java # 健康检查接口
│ └── BusinessController.java # 业务 REST 接口
├── model/
│ └── BusinessItem.java # 业务数据模型
└── service/
└── BusinessService.java # 业务逻辑(内存假数据)
```bash
uvicorn app.main:app --reload --port 8000
```
### 扩展说明
访问 http://127.0.0.1:8000/docs 查看自动生成的 API 文档Swagger UI
- `repository/` 目录可扩展为数据库 Repository 层
- `service/` 中注入 Repository 即可切换为真实数据源
- 配置文件已预留 Spring Data JPA / MyBatis 相关配置注释
## 运行测试
```bash
cd codegen-runs/codegen_a2cef5070965479b93c5b3c07d4c8216
pytest tests/ -v
```
## 快速验证
启动服务后,在另一个终端执行:
```bash
# 获取所有待办事项
curl http://127.0.0.1:8000/todos
# 创建新待办事项
curl -X POST http://127.0.0.1:8000/todos \
-H "Content-Type: application/json" \
-d '{"title": "学习 FastAPI", "completed": false}'
```

1
app/__init__.py Normal file
View File

@ -0,0 +1 @@
# app 包初始化文件

91
app/main.py Normal file
View File

@ -0,0 +1,91 @@
"""
FastAPI 主应用入口
提供待办事项Todo管理的 RESTful API
使用内存假数据存储无需外部数据库
"""
from fastapi import FastAPI, HTTPException, status
from app.services import (
TodoService,
TodoCreate,
TodoUpdate,
TodoResponse,
)
app = FastAPI(
title="Todo 管理服务",
description="一个基于 FastAPI 的简单待办事项管理服务示例",
version="1.0.0",
)
# 全局服务实例(使用内存假数据)
todo_service = TodoService()
# ──────────────────────────────────────────────
# API 路由
# ──────────────────────────────────────────────
@app.get("/", tags=["健康检查"])
async def root():
"""服务根路径,返回基本信息。"""
return {
"service": "Todo 管理服务",
"version": "1.0.0",
"docs": "/docs",
}
@app.get("/todos", response_model=list[TodoResponse], tags=["待办事项"])
async def list_todos():
"""获取所有待办事项列表。"""
return todo_service.list_todos()
@app.get("/todos/{todo_id}", response_model=TodoResponse, tags=["待办事项"])
async def get_todo(todo_id: int):
"""根据 ID 获取单个待办事项。"""
todo = todo_service.get_todo(todo_id)
if todo is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"待办事项 {todo_id} 不存在",
)
return todo
@app.post(
"/todos",
response_model=TodoResponse,
status_code=status.HTTP_201_CREATED,
tags=["待办事项"],
)
async def create_todo(todo_in: TodoCreate):
"""创建新的待办事项。"""
return todo_service.create_todo(todo_in)
@app.put("/todos/{todo_id}", response_model=TodoResponse, tags=["待办事项"])
async def update_todo(todo_id: int, todo_in: TodoUpdate):
"""更新指定待办事项。"""
todo = todo_service.update_todo(todo_id, todo_in)
if todo is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"待办事项 {todo_id} 不存在",
)
return todo
@app.delete("/todos/{todo_id}", status_code=status.HTTP_204_NO_CONTENT, tags=["待办事项"])
async def delete_todo(todo_id: int):
"""删除指定待办事项。"""
deleted = todo_service.delete_todo(todo_id)
if not deleted:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"待办事项 {todo_id} 不存在",
)
return None

101
app/services.py Normal file
View File

@ -0,0 +1,101 @@
"""
业务逻辑层 使用内存假数据实现 Todo CRUD 操作
所有数据存储在内存字典中服务重启后数据会丢失
"""
from __future__ import annotations
from typing import Optional
from pydantic import BaseModel, Field
# ──────────────────────────────────────────────
# Pydantic 模型(请求 / 响应)
# ──────────────────────────────────────────────
class TodoCreate(BaseModel):
"""创建待办事项的请求体。"""
title: str = Field(..., min_length=1, max_length=200, description="待办事项标题")
completed: bool = Field(False, description="是否已完成")
class TodoUpdate(BaseModel):
"""更新待办事项的请求体(部分更新)。"""
title: Optional[str] = Field(None, min_length=1, max_length=200, description="待办事项标题")
completed: Optional[bool] = Field(None, description="是否已完成")
class TodoResponse(BaseModel):
"""待办事项的响应体。"""
id: int = Field(..., description="待办事项 ID")
title: str = Field(..., description="待办事项标题")
completed: bool = Field(..., description="是否已完成")
model_config = {"from_attributes": True}
# ──────────────────────────────────────────────
# 内存假数据存储
# ──────────────────────────────────────────────
class TodoService:
"""待办事项服务 —— 使用内存字典存储数据。"""
def __init__(self) -> None:
self._todos: dict[int, dict] = {}
self._next_id: int = 1
self._init_mock_data()
def _init_mock_data(self) -> None:
"""初始化一批假数据,方便演示。"""
mock_todos = [
{"title": "学习 FastAPI", "completed": False},
{"title": "编写单元测试", "completed": False},
{"title": "阅读 Python 文档", "completed": True},
{"title": "完成项目报告", "completed": False},
{"title": "锻炼身体 30 分钟", "completed": True},
]
for item in mock_todos:
self.create_todo(TodoCreate(**item))
def list_todos(self) -> list[TodoResponse]:
"""返回所有待办事项。"""
return [TodoResponse(**todo) for todo in self._todos.values()]
def get_todo(self, todo_id: int) -> Optional[TodoResponse]:
"""根据 ID 获取单个待办事项,不存在则返回 None。"""
todo = self._todos.get(todo_id)
if todo is None:
return None
return TodoResponse(**todo)
def create_todo(self, todo_in: TodoCreate) -> TodoResponse:
"""创建新的待办事项并返回。"""
todo_id = self._next_id
self._next_id += 1
todo = {
"id": todo_id,
"title": todo_in.title,
"completed": todo_in.completed,
}
self._todos[todo_id] = todo
return TodoResponse(**todo)
def update_todo(self, todo_id: int, todo_in: TodoUpdate) -> Optional[TodoResponse]:
"""部分更新指定待办事项,不存在则返回 None。"""
todo = self._todos.get(todo_id)
if todo is None:
return None
update_data = todo_in.model_dump(exclude_unset=True)
todo.update(update_data)
return TodoResponse(**todo)
def delete_todo(self, todo_id: int) -> bool:
"""删除指定待办事项,成功返回 True不存在返回 False。"""
if todo_id not in self._todos:
return False
del self._todos[todo_id]
return True

File diff suppressed because one or more lines are too long

6
requirements.txt Normal file
View File

@ -0,0 +1,6 @@
fastapi==0.115.6
uvicorn==0.34.0
pydantic==2.10.4
httpx==0.28.1
pytest==8.3.4
pytest-asyncio==0.25.0

111
tests/test_basic.py Normal file
View File

@ -0,0 +1,111 @@
"""
基础单元测试 测试 TodoService 的核心功能
运行方式
cd codegen-runs/codegen_a2cef5070965479b93c5b3c07d4c8216
pytest tests/ -v
"""
import pytest
from app.services import TodoService, TodoCreate, TodoUpdate
@pytest.fixture
def service() -> TodoService:
"""每个测试用例使用独立的 TodoService 实例。"""
return TodoService()
class TestTodoService:
"""TodoService 核心功能测试。"""
def test_list_todos_should_return_mock_data(self, service: TodoService):
"""测试初始化时自动生成假数据。"""
todos = service.list_todos()
assert len(todos) == 5 # 初始化了 5 条假数据
def test_create_todo_should_return_created_todo(self, service: TodoService):
"""测试创建待办事项。"""
todo_in = TodoCreate(title="新任务", completed=True)
todo = service.create_todo(todo_in)
assert todo.title == "新任务"
assert todo.completed is True
assert todo.id > 0
def test_get_todo_should_return_correct_todo(self, service: TodoService):
"""测试根据 ID 获取待办事项。"""
# 先创建
created = service.create_todo(TodoCreate(title="测试任务"))
# 再获取
fetched = service.get_todo(created.id)
assert fetched is not None
assert fetched.id == created.id
assert fetched.title == "测试任务"
def test_get_todo_should_return_none_when_not_found(self, service: TodoService):
"""测试获取不存在的待办事项返回 None。"""
todo = service.get_todo(99999)
assert todo is None
def test_update_todo_should_update_title(self, service: TodoService):
"""测试部分更新待办事项的标题。"""
created = service.create_todo(TodoCreate(title="旧标题"))
updated = service.update_todo(created.id, TodoUpdate(title="新标题"))
assert updated is not None
assert updated.title == "新标题"
assert updated.completed is False # 未更新的字段保持不变
def test_update_todo_should_update_completed(self, service: TodoService):
"""测试部分更新待办事项的完成状态。"""
created = service.create_todo(TodoCreate(title="任务", completed=False))
updated = service.update_todo(created.id, TodoUpdate(completed=True))
assert updated is not None
assert updated.completed is True
assert updated.title == "任务" # 未更新的字段保持不变
def test_update_todo_should_return_none_when_not_found(self, service: TodoService):
"""测试更新不存在的待办事项返回 None。"""
result = service.update_todo(99999, TodoUpdate(title=""))
assert result is None
def test_delete_todo_should_return_true(self, service: TodoService):
"""测试删除存在的待办事项返回 True。"""
created = service.create_todo(TodoCreate(title="待删除"))
result = service.delete_todo(created.id)
assert result is True
# 确认已删除
assert service.get_todo(created.id) is None
def test_delete_todo_should_return_false_when_not_found(self, service: TodoService):
"""测试删除不存在的待办事项返回 False。"""
result = service.delete_todo(99999)
assert result is False
def test_list_todos_after_create_and_delete(self, service: TodoService):
"""测试增删操作后列表长度的变化。"""
initial_count = len(service.list_todos())
# 创建 2 个
t1 = service.create_todo(TodoCreate(title="A"))
t2 = service.create_todo(TodoCreate(title="B"))
assert len(service.list_todos()) == initial_count + 2
# 删除 1 个
service.delete_todo(t1.id)
assert len(service.list_todos()) == initial_count + 1
# 删除另一个
service.delete_todo(t2.id)
assert len(service.list_todos()) == initial_count
@pytest.mark.asyncio
async def test_fastapi_health_check():
"""简单的 FastAPI 健康检查测试(使用 TestClient"""
from httpx import AsyncClient, ASGITransport
from app.main import app
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as client:
response = await client.get("/")
assert response.status_code == 200
data = response.json()
assert "service" in data
assert data["service"] == "Todo 管理服务"