面向有 Java/Spring 背景的开发者,结合本项目(mystu)的实际代码,快速理解 Python 基础与 REST API 编写方式。


1. 为什么选 Python 写 API?

如果你熟悉 Spring Boot + Controller + DTO,那么 FastAPI + Router + Pydantic Model 会非常接近:

Java (Spring) Python (FastAPI)
@RestController APIRouter / 路由函数
@RequestBody UserDTO 函数参数 + Pydantic 模型
@GetMapping / @PostMapping @router.get / @router.post
Jackson 序列化 JSON Pydantic 自动校验与序列化
application.yml 端口配置 uvicorn.run(host, port)
Maven/Gradle 依赖 pyproject.toml / pip
包名 com.example.service 模块路径 mystu.controller

Python 的优势在于语法简洁、AI/数据分析生态丰富;FastAPI 则提供了类型提示、自动文档(Swagger UI)和高性能异步能力。


2. Python 基础:Java 开发者速查

2.1 缩进代替大括号

Python 用 缩进(通常 4 空格) 表示代码块,没有 {}

# Java
if (x > 0) {
    doSomething();
}

# Python
if x > 0:
    do_something()

2.2 命名习惯

场景 Java Python(惯例)
类名 UserService UserService
变量/函数 getUserName get_user_name
常量 MAX_SIZE MAX_SIZE
私有成员 private field _field(约定)

Python 没有真正的 private,单下划线 _ 表示「内部使用」,双下划线 __ 会触发名称改写,日常很少用。

2.3 类型注解(Type Hints)

Python 3 支持可选类型注解,FastAPI heavily 依赖它:

# Java
public String hello(String name) { ... }

# Python
def hello(name: str) -> str:
    return f"Hello, {name}"
  • strintlist[str] 类似 Java 泛型
  • -> str 表示返回值类型
  • 注解 不会强制运行时检查(除非用 Pydantic / 静态工具),但 FastAPI 会用来生成文档和校验

2.4 模块与包(对比 Java package)

mystu/                          # 项目根目录
├── main.py                     # 入口,类似 Application.main
├── pyproject.toml              # 依赖配置,类似 pom.xml
└── mystu/                      # 包根目录(与项目名同名很常见)
    ├── controller/
    │   ├── __init__.py         # 包标识文件,类似 package-info
    │   └── api.py              # 路由,类似 Controller
    └── entity/
        ├── apireq.py           # 请求 DTO
        └── apirsp.py           # 响应 DTO

导入方式:

# 绝对导入(推荐)
from mystu.entity import apireq, apirsp

# 相对导入(包内部)
from .api import router

注意:entity 目录下每个 .py 文件是一个 模块apireq 是模块名,apireq.Request 才是类名。
这是 Java 开发者常见的第一个坑——不要把模块名当成类型用

2.5 虚拟环境

类似 Java 里每个项目独立的 JDK + 本地 Maven 仓库:

# 创建虚拟环境
python -m venv .venv

# Windows 激活
.venv\Scripts\activate

# 安装依赖(本项目用 pyproject.toml)
pip install fastapi uvicorn
# 或使用 uv
uv sync

依赖写在 pyproject.toml

[project]
name = "mystu"
requires-python = ">=3.12"
dependencies = [
    "fastapi>=0.136.3",
    "uvicorn>=0.48.0",
]

3. 核心概念:Pydantic 模型 ≈ Java DTO

3.1 请求体

Java:

public class Request {
    @NotBlank
    private String keyword;
}

Python(本项目 mystu/entity/apireq.py):

from pydantic import BaseModel, Field

class Request(BaseModel):
    keyword: str = Field(..., description="请用户输入关键字")
  • BaseModel:类似 Lombok @Data + Bean Validation 合体
  • Field(...)... 表示必填,类似 @NotNull
  • FastAPI 收到 JSON 后会 自动反序列化 + 校验,失败则返回 422

3.2 响应体

mystu/entity/apirsp.py

from pydantic import BaseModel

class Response(BaseModel):
    data: str

返回时构造模型实例,FastAPI 自动转成 JSON:

return apirsp.Response(data="你好")

不要直接 return "你好"——类型注解是 Response 时,应返回对应结构(或 dict 字段匹配)。


4. 编写 API:Router ≈ Controller

4.1 创建 FastAPI 应用

mystu/controller/__init__.py

from fastapi import FastAPI
from .api import router

myApp = FastAPI(
    title="mytest",
    version="1.0",
)

myApp.include_router(router)

对比 Spring:

@SpringBootApplication
public class Application { ... }

// 或在配置类里注册路由前缀

4.2 定义路由

mystu/controller/api.py

from fastapi import APIRouter
from mystu.entity import apireq, apirsp

router = APIRouter(prefix="/agent/api", tags=["test"])

@router.post("/test")
async def test(request: apireq.Request) -> apirsp.Response:
    return apirsp.Response(data="你好")

逐行对照 Java:

代码 含义
APIRouter(prefix=...) 类级别 @RequestMapping("/agent/api")
@router.post("/test") @PostMapping("/test")
async def 异步方法;简单 CRUD 也可写普通 def
request: apireq.Request @RequestBody Request request
-> apirsp.Response 方法返回类型 / ResponseEntity 泛型

完整 URL:POST http://localhost:5000/agent/api/test

4.3 常见错误:类型注解写错

错误写法(会启动失败):

async def test(request: apireq) -> apirsp:  # apireq/apirsp 是模块,不是类型
    return "你好"

报错类似:

FastAPIError: Invalid args for response field! ...
Hint: check that <module 'mystu.entity.apirsp'> is a valid Pydantic field type.

正确写法:

async def test(request: apireq.Request) -> apirsp.Response:
    return apirsp.Response(data="你好")

5. 启动服务:uvicorn ≈ 内嵌 Tomcat

5.1 推荐写法

main.py

import uvicorn
from mystu.controller import myApp

if __name__ == "__main__":
    uvicorn.run(
        myApp,              # 直接传入 FastAPI 实例
        host="0.0.0.0",
        port=5000,
        reload=True,        # 开发热重载,类似 spring-boot-devtools
    )

或使用字符串形式(便于 reload 子进程加载):

uvicorn.run("mystu.controller:myApp", host="0.0.0.0", port=5000, reload=True)

5.2 async 入口的坑

若写成:

async def _serve():
    config = uvicorn.Config(myApp, host="0.0.0.0", port=5000)
    await uvicorn.Server(config).serve()

if __name__ == "__main__":
    _serve()  # ❌ 协程未被 await

会警告 coroutine '_serve' was never awaited,进程立刻退出。
需要:

import asyncio
asyncio.run(_serve())

对 Java 开发者来说:Python 的 async def 类似 CompletableFuture调用 async 函数不会自动执行,必须用事件循环驱动。

5.3 命令行启动

uvicorn mystu.controller:myApp --host 0.0.0.0 --port 5000 --reload

6. 自动 API 文档

启动后访问:

  • Swagger UI:http://localhost:5000/docs
  • ReDoc:http://localhost:5000/redoc

相当于 Spring 集成 springdoc-openapi,但 零配置
Pydantic 模型的 Field(description=...) 会直接出现在文档里。


7. 测试接口

7.1 curl

curl -X POST "http://localhost:5000/agent/api/test" \
  -H "Content-Type: application/json" \
  -d "{\"keyword\": \"铁矿石\"}"

期望响应:

{"data": "你好"}

7.2 Python requests

import requests

resp = requests.post(
    "http://localhost:5000/agent/api/test",
    json={"keyword": "铁矿石"},
)
print(resp.status_code, resp.json())

8. 异常处理(对比 Spring)

Java:

@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<?> handle(...) { ... }

// 或
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "not found");

FastAPI:

from fastapi import HTTPException

@router.get("/items/{item_id}")
async def get_item(item_id: int):
    if item_id <= 0:
        raise HTTPException(status_code=400, detail="item_id 必须大于 0")
    return {"item_id": item_id}

全局异常处理器:

from fastapi import Request
from fastapi.responses import JSONResponse

@myApp.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
    return JSONResponse(status_code=400, content={"message": str(exc)})

9. 依赖注入(进阶预览)

FastAPI 内置 Depends,概念接近 Spring 的 @Autowired / 构造器注入:

from fastapi import Depends

def get_db():
    db = connect()
    try:
        yield db
    finally:
        db.close()

@router.get("/users")
async def list_users(db=Depends(get_db)):
    return db.query_users()

初学阶段可先写简单函数,等项目变大再引入分层(service / repository)。


10. Java vs Python Web 思维对照小结

话题 Java 习惯 Python/FastAPI 习惯
分层 Controller → Service → Repository Router → 函数/Service 模块
DTO Java Bean + Validation Pydantic BaseModel
配置 application.yml 环境变量 / pydantic-settings / 直接代码
运行 mvn spring-boot:run python main.pyuvicorn ...
测试 JUnit + MockMvc pytest + httpx.AsyncClient
并发 线程池 / WebFlux 响应式 async/await + ASGI
接口文档 常需额外配置 内置 /docs

11. 本项目最小闭环回顾

  1. 定义模型entity/apireq.pyentity/apirsp.py
  2. 写路由controller/api.py
  3. 组装应用controller/__init__.py 创建 myAppinclude_router
  4. 启动main.pyuvicorn.run(myApp, ...)
  5. 调试:浏览器打开 /docs 或 curl 发 POST

目录结构清晰后,后续加业务只需:

  • entity/ 增加请求/响应模型
  • controller/ 增加路由函数
  • 复杂逻辑抽到 service/(可按 Java 分层习惯新建)

12. 学习建议(给 Java 背景的你)

  1. 先接受「动态 + 简洁」:少写样板代码,但类型注解仍要写好,方便 IDE 和 FastAPI。
  2. 分清模块与类import apireq 导入的是文件模块,类型用 apireq.Request
  3. 善用 /docs:比 Postman 更快验证接口。
  4. 异步不必强求:CPU 简单逻辑用 def 即可;IO 密集(大量 HTTP/DB)再学 async
  5. 下一步:学习 pytest 测 API、SQLAlchemy 连数据库、pydantic-settings 读配置——都和你熟悉的 Spring 生态一一对应。

参考


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐