PART 3 - 后端(FastAPI & Spring Boot)
后端的小伙伴们看过来,适合你们的在这里!这部分主要围绕我个人在
Spring Boot (Java/Kotlin) 和 FastAPI (Python) 项目中沉淀下来的规范和最佳实践。当然,很多思想同样适用于 Gin (Go)、Express (TypeScript) 等其他现代后端框架。后端的稳定性和安全性是整个应用的基石。一个清晰、分层、可维护的后端项目,不仅能让开发和协作丝般顺滑,还能在面对高并发、复杂业务和安全威胁时游刃有余。
3.1 - 项目结构规范
一个好的项目结构是成功的开始。它能让开发者快速定位代码,理解模块职责,降低新成员的上手门槛。
Spring Boot 项目结构 (Maven/Gradle)
Spring Boot 项目通常遵循标准的 Maven/Gradle 目录结构,并在此基础上进行分包。推荐采用按层或按功能划分的方式。
推荐结构 (按层划分):
src
└── main
├── java
│ └── com
│ └── example
│ └── myapp
│ ├── MyApplication.java // Spring Boot 启动类
│ ├── config // 配置类 (如 Spring Security, MyBatis, Swagger)
│ ├── controller // 控制层 (处理 HTTP 请求, 调用 Service)
│ ├── service // 业务逻辑层
│ │ └── impl // Service 的实现类
│ ├── repository / mapper // 数据访问层 (JPA Repository, MyBatis Mapper)
│ ├── model // 数据模型层
│ │ ├── entity // 数据库实体 (Entity)
│ │ └── dto // 数据传输对象 (Data Transfer Object)
│ ├── exception // 自定义异常及全局异常处理器
│ └── utils // 工具类
└── resources
├── application.yml // 主配置文件
├── application-dev.yml // 开发环境配置
├── application-prod.yml // 生产环境配置
├── static // 静态资源
├── templates // 模板文件 (如 Thymeleaf)
└── mapper // MyBatis XML 文件controller: 只负责接收前端请求、参数校验、调用service层,然后返回响应。保持controller的轻薄。service: 核心业务逻辑的实现地。复杂的业务流程、事务管理都在这一层。repository: 与数据库直接交互,负责数据的增删改查。model:entity: 与数据库表结构一一对应,由 ORM 框架管理。dto: 用于在不同层之间(特别是controller和service)传输数据,避免直接暴露数据库实体,实现解耦。 (这里如果复杂也可能会 entity dto vo 各个有对应的包)
exception: 定义全局异常处理器 (@RestControllerAdvice),业务Exception定义等 ,捕获并格式化异常信息,返回统一的错误响应。
当前好多后端用了 Spring Boot
FastAPI 项目结构
FastAPI 社区推崇模块化和显式依赖,结构相对灵活,但遵循一定的最佳实践能让项目更清晰。
推荐结构:
.
├── app // 应用主目录
│ ├── __init__.py
│ ├── main.py // FastAPI 应用实例和启动入口
│ ├── api // API 路由层
│ │ ├── __init__.py
│ │ └── v1 // API 版本
│ │ ├── __init__.py
│ │ ├── endpoints // 按资源划分路由文件
│ │ │ ├── user.py
│ │ │ └── article.py
│ │ └── deps.py // 依赖注入项 (如获取当前用户, 数据库 session)
│ ├── core // 核心配置
│ │ ├── __init__.py
│ │ └── config.py // 配置加载 (如环境变量)
│ ├── crud // 数据库操作层 (CRUD: Create, Read, Update, Delete)
│ │ ├── __init__.py
│ │ ├── crud_user.py
│ │ └── base.py // 通用 CRUD 基类
│ ├── models // 数据库模型 (SQLAlchemy Models)
│ │ ├── __init__.py
│ │ └── user.py
│ ├── schemas // 数据校验层 (Pydantic Schemas)
│ │ ├── __init__.py
│ │ └── user.py // 定义请求体、响应体的 Pydantic 模型
│ └── db // 数据库相关
│ ├── __init__.py
│ └── session.py // 数据库引擎和 session 创建
├── .env // 环境变量文件
├── requirements.txt // Python 依赖
└── ...main.py: 初始化FastAPIapp,并使用include_router挂载api目录下的各个路由。api/endpoints: 类似于 Spring Boot 的controller,定义路径操作函数(@app.get,@app.post等)。crud: 类似于 Spring Boot 的repository,封装了对数据库模型的直接操作,供api层调用。models: SQLAlchemy 的 ORM 模型,对应数据库表。schemas: Pydantic 模型,这是 FastAPI 的精髓之一。它负责请求/响应数据的定义、校验和序列化,功能上等同于 Spring Boot 的 DTO + Validation。
3.2 - API 设计与实现
统一响应格式
如 PART 1 所述,后端需要返回统一的 JSON 结构。我们可以通过封装一个通用响应类来实现。
Spring Boot 实现:
创建一个泛型 Result 类。
// Result.java
public class Result<T> {
private int code;
private String msg;
private T data;
// 构造函数、Getter/Setter 省略...
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(0);
result.setMsg("成功");
result.setData(data);
return result;
}
public static <T> Result<T> error(int code, String msg) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMsg(msg);
return result;
}
}
// 在 Controller 中使用
@GetMapping("/user/{id}")
public Result<UserDTO> getUserById(@PathVariable Long id) {
UserDTO user = userService.findUserById(id);
return Result.success(user);
}FastAPI 实现:
同样可以创建一个通用的响应模型,或直接在路由函数中构建字典。
# schemas/response.py
from typing import Generic, TypeVar, Optional
from pydantic import BaseModel, Field
T = TypeVar('T')
class ResponseModel(BaseModel, Generic[T]):
code: int = Field(0, description="状态码")
msg: str = Field("成功", description="消息")
data: Optional[T] = None
# 在 endpoint 中使用
from app.schemas.response import ResponseModel
from app.schemas.user import User # Pydantic schema for user
@router.get("/{user_id}", response_model=ResponseModel[User])
def read_user(user_id: int):
# db_user = crud.user.get(db, id=user_id)
# ...
# return {"code": 0, "msg": "成功", "data": db_user}
# 或者直接返回 ORM model, FastAPI 会自动序列化
return {"data": db_user} # code 和 msg 会使用默认值使用 DTO/Schema
永远不要直接将数据库实体(Entity/ORM Model)直接暴露给前端!
- 安全: 避免泄露数据库结构和不应被前端感知的字段(如密码哈希、内部状态)。
- 解耦: API 的形态不应被数据库的结构所绑定。数据库表结构可能会变,但 API 可以保持向后兼容。
- 灵活: 可以根据不同场景(如创建、更新、列表展示)定制不同的 DTO/Schema,只包含必要的字段。
Spring Boot 示例 (UserDTO.java):
public class UserDTO {
private Long id;
private String username;
private String avatar;
// 没有 password 字段
}FastAPI 示例 (schemas/user.py):
from pydantic import BaseModel
# 用于创建用户的请求体
class UserCreate(BaseModel):
username: str
password: str
# 用于响应的 Schema
class User(BaseModel):
id: int
username: str
avatar: str | None = None
class Config:
from_attributes = True # 兼容 ORM 模型3.3 - 安全规范
后端是安全的第一道,也是最重要的一道防线。
严格禁止任何未经验证鉴权的系统上线,开发测试时就应配有完善的鉴权逻辑。
认证与授权
通常使用 JWT (JSON Web Token) 实现。
- 登录接口: 用户提供凭证(用户名/密码),验证成功后,后端生成一个 JWT 并返回。
- 后续请求: 前端在请求头
Authorization中携带Bearer <token>。 - 后端验证: 后端通过中间件(Middleware)或拦截器(Interceptor/Filter)在每个受保护的请求到达前,解析并验证 JWT 的有效性。
Spring Boot: 强烈推荐使用 Spring Security。它提供了完整的认证和授权框架,可以方便地集成 JWT。通过配置可以实现对 URL 的精细化权限控制。
FastAPI: 通过 Depends 实现一个依赖项来验证 Token,可以非常方便地应用到需要保护的路由上。
# api/v1/deps.py
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
# 这里是解码和验证 JWT 的逻辑
# ...
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
)
return user输入验证
绝不相信来自客户端的任何数据!
- Spring Boot: 使用
jakarta.validation(以前是javax.validation)注解,在 DTO 的字段上添加@NotNull,@Size,@Email等,并在 Controller 方法参数前加上@Valid。
// CreateUserDTO.java
public class CreateUserDTO {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
private String username;
// ...
}- FastAPI: 这是 FastAPI 的强项。Pydantic Schema 本身就是天然的验证器。如果请求数据不符合 Schema 定义(类型、必填项等),FastAPI 会自动返回一个详细的
422 Unprocessable Entity错误响应。
防止 SQL 注入
永远使用 ORM 或参数化查询! 严禁手动拼接 SQL 字符串。
- Spring Boot: 使用
Spring Data JPA(不建议,都 5202 年了,不过也可能有人会用) 或MyBatis。它们底层都使用了PreparedStatement,可以有效防止 SQL 注入。 - FastAPI: 使用
SQLAlchemyORM,通过构建查询表达式来操作数据库,同样是安全的。
3.4 - 代码风格与注释
命名规范
- Java/Kotlin:
- 类名:
UpperCamelCase(帕斯卡命名法),如UserController。 - 方法/变量名:
lowerCamelCase(小驼峰命名法),如getUserById。 - 常量:
UPPER_SNAKE_CASE(大写下划线),如MAX_LOGIN_ATTEMPTS。
- 类名:
- Python:
- 遵循
PEP 8规范。 - 模块/包/变量/函数名:
lower_snake_case(小写下划线),如get_user_by_id。 - 类名:
CapitalizedWords(同帕斯卡),如UserSchema。
- 遵循
注释
和前端一样,注释至关重要。
- 公共 API: 必须有详细的文档注释(JavaDoc 或 Python Docstrings),说明其功能、参数、返回值和可能抛出的异常。
- 复杂业务逻辑: 在代码块前添加注释,解释这段代码的业务目的和实现思路。
- TODO / FIXME: 明确标注待办事项或需要修复的问题,并最好署名和日期。
JavaDoc 示例:
/**
* 根据用户ID查找用户,并转换为DTO.
* @param id 用户的唯一标识ID
* @return 包含用户信息的DTO对象
* @throws UserNotFoundException 如果用户不存在
*/
public UserDTO findUserById(Long id) {
// ...
}Python Docstring 示例 (Google Style):
def get_user_by_id(db: Session, user_id: int) -> models.User:
"""Gets a user by their ID.
Args:
db: The database session.
user_id: The ID of the user to retrieve.
Returns:
The user object from the database.
"""
# ...一个优秀的后端系统,离不开这些良好习惯的日积月累。与前端规范结合起来,就能构建出一个真正高质量的全栈项目。
最后更新于 2025/9/26 08:12:33
更新历史
本书还在编写中..
前往 Github Repo 参与讨论或贡献内容。