Flask/Django vs Spring:Python Web开发快速上手
摘要:Java有Spring,Python有Flask和Django。本文对比三种框架的设计理念和入门路径。
写在前面
作为一个Java工程师,你一定对Spring Boot的"约定优于配置"印象深刻。Python的Web框架同样遵循这一理念,但实现方式不同。
Spring强调"全功能、企业级",Flask强调"微框架、灵活扩展",Django强调"全功能、敏捷开发"。
一、框架生态对比
1.1 Java的Spring帝国
Spring Boot
├── Spring MVC (Web层)
├── Spring Data (数据层)
├── Spring Security (安全)
├── Spring Cloud (微服务)
└── ... (无数子项目)
Spring Boot的核心优势:
- 自动配置(Auto Configuration)
- 起步依赖(Starter Dependencies)
- 嵌入式服务器
- 生产级特性(Actuator、Metrics)
1.2 Python的框架生态
Python Web框架
├── Django # 全功能框架
│ ├── ORM
│ ├── Admin
│ ├── Templates
│ └── Auth
├── Flask # 微框架
│ ├── 核心
│ └── 扩展(Flask-SQLAlchemy, Flask-Login等)
├── FastAPI # 现代异步框架
│ ├── 自动文档
│ ├── 类型提示
│ └── 异步支持
└── Pyramid # 介于两者之间
二、Flask:微框架的典范
2.1 核心概念对比
| Spring Boot | Flask |
|---|---|
@RestController | @app.route() |
@RequestMapping | app.route() |
@PathVariable | <variable_name> |
@RequestParam | request.args.get() |
@RequestBody | request.get_json() |
| 返回对象/JSON | return jsonify(data) |
2.2 最小应用
// Spring Boot
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}
# Flask
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route("/api/users/<int:id>")
def get_user(id):
user = user_service.find_by_id(id)
return jsonify(user)
if __name__ == "__main__":
app.run(debug=True)
2.3 请求处理对比
// Spring Boot - 完整示例
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping
public User createUser(@RequestBody @Valid UserRequest request) {
return userService.create(request);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id,
@RequestBody UserRequest request) {
return userService.update(id, request);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.delete(id);
}
@GetMapping
public List<User> listUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return userService.findAll(page, size);
}
}
# Flask - 完整示例
from flask import Flask, jsonify, request
from flask.views import MethodView
app = Flask(__name__)
class UserView(MethodView):
def get(self, user_id=None):
if user_id is None:
page = request.args.get("page", 0, type=int)
size = request.args.get("size", 10, type=int)
return jsonify(user_service.find_all(page, size))
return jsonify(user_service.find_by_id(user_id))
def post(self):
data = request.get_json()
return jsonify(user_service.create(data)), 201
def put(self, user_id):
data = request.get_json()
return jsonify(user_service.update(user_id, data))
def delete(self, user_id):
user_service.delete(user_id)
return "", 204
# 注册路由
app.add_url_rule("/api/users", view_func=UserView.as_view("users"))
app.add_url_rule("/api/users/<int:user_id>", view_func=UserView.as_view("user"))
三、Django:全功能框架
3.1 Django vs Spring Boot
| 概念 | Django | Spring Boot |
|---|---|---|
| 项目结构 | django-admin startproject | spring initializr |
| 应用 | App | Module/Component |
| ORM | Django ORM | JPA/Hibernate |
| 路由 | urls.py | @RequestMapping |
| 视图 | FBV / Class-based | Controller |
| 模板 | Django Template | Thymeleaf/Freemarker |
| Admin | 内置Admin站点 | Spring Admin |
| 配置 | settings.py | application.yml |
3.2 Django项目结构
myproject/
├── manage.py # Django CLI工具
├── myproject/
│ ├── __init__.py
│ ├── settings.py # 配置文件
│ ├── urls.py # 根路由
│ ├── wsgi.py # WSGI入口
│ └── asgi.py # ASGI入口
└── myapp/
├── __init__.py
├── models.py # 数据模型
├── views.py # 视图
├── urls.py # 应用路由
├── admin.py # Admin配置
└── migrations/ # 数据库迁移
3.3 Django ORM vs JPA
// Spring Data JPA
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(unique = true)
private String email;
private Integer age;
@ManyToMany
@JoinTable(name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
}
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByAgeGreaterThan(int age);
Optional<User> findByEmail(String email);
@Query("SELECT u FROM User u WHERE u.name LIKE %:name%")
List<User> searchByName(@Param("name") String name);
}
# Django ORM
from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
age = models.IntegerField(null=True, blank=True)
roles = models.ManyToManyField("Role", through="UserRole")
class Meta:
db_table = "users"
def __str__(self):
return self.name
# 查询
User.objects.all()
User.objects.filter(age__gt=18)
User.objects.get(email="alice@example.com")
User.objects.filter(name__contains="Alice")
3.4 Django REST Framework
// Spring Data REST + Jackson
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String name;
private String email;
}
@RestRepositoryResource
public interface UserRepository extends JpaRepository<User, Long> {
}
# Django REST Framework
from rest_framework import serializers, viewsets
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["id", "name", "email"]
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# 自动生成CRUD + 列表 + 分页 + 过滤 + 搜索
# API文档:http://localhost:8000/docs/
四、FastAPI:现代异步框架
4.1 概念对比
| Spring | FastAPI |
|---|---|
@RestController | @app.get/post/put/delete() |
@RequestBody | Pydantic Model |
CompletableFuture | async/await |
@Async | async def |
| Spring Doc (OpenAPI) | 自动生成 |
| WebFlux | 原生异步 |
4.2 FastAPI示例
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class User(BaseModel):
name: str
email: str
age: Optional[int] = None
class UserResponse(BaseModel):
id: int
name: str
email: str
users_db = []
@app.post("/users", response_model=UserResponse)
async def create_user(user: User):
new_user = UserResponse(
id=len(users_db) + 1,
name=user.name,
email=user.email
)
users_db.append(new_user)
return new_user
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
return users_db[user_id - 1]
@app.get("/users")
async def list_users(skip: int = 0, limit: int = 10):
return users_db[skip:skip+limit]
FastAPI自动:
- 生成OpenAPI文档:
/docs(Swagger UI)或/redoc - 验证请求数据(Pydantic)
- 生成响应数据
- 支持异步
五、中间件与拦截器
5.1 Java过滤器/拦截器
// Spring Boot 过滤器
@Component
@Order(1)
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
long start = System.currentTimeMillis();
chain.doFilter(request, response);
log.info("耗时: {}ms", System.currentTimeMillis() - start);
}
}
// 拦截器
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String token = request.getHeader("Authorization");
if (!isValid(token)) {
response.setStatus(401);
return false;
}
return true;
}
}
5.2 Flask中间件
# Flask 装饰器实现
from functools import wraps
import time
def log_request(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"耗时: {time.time() - start:.2f}ms")
return result
return wrapper
@app.route("/api/users")
@log_request
def get_users():
return jsonify(users)
# Flask 中间件(WSGI级别)
def middleware(app):
def logMiddleware(environ, start_response):
# 请求前处理
response = app(environ, start_response)
# 响应后处理
return response
return logMiddleware
5.3 Django中间件
# Django 中间件
class LoggingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start = time.time()
response = self.get_response(request)
duration = time.time() - start
print(f"请求 {request.path} 耗时 {duration:.2f}ms")
return response
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.middleware.common.CommonMiddleware',
'myapp.middleware.LoggingMiddleware',
]
六、依赖注入对比
6.1 Java Spring DI
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User findById(Long id) {
return userRepository.findById(id).orElseThrow();
}
}
@RestController
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
}
6.2 Flask依赖注入
# Flask 手动DI
class UserService:
def __init__(self, repository):
self.repository = repository
def find_by_id(self, user_id):
return self.repository.find_by_id(user_id)
# 手动组装
user_repository = UserRepository()
user_service = UserService(user_repository)
user_controller = UserController(user_service)
# Flask-Injector(可选)
from flask_injector import FlaskInjector
FlaskInjector(app=app, modules=[UserModule])
6.3 FastAPI依赖注入
# FastAPI 内置依赖注入
from fastapi import Depends
def get_user_repository():
return UserRepository()
@app.post("/users")
async def create_user(
user: User,
repo: UserRepository = Depends(get_user_repository)
):
return repo.create(user)
# 带缓存的依赖
from functools import lru_cache
@lru_cache()
def get_settings():
return Settings()
七、错误处理对比
7.1 Spring全局异常
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result handleBusiness(BusinessException e) {
return Result.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleValidation(MethodArgumentNotValidException e) {
String msg = e.getBindingResult().getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return Result.error("VALIDATION_ERROR", msg);
}
}
7.2 Flask错误处理
from flask import jsonify
@app.errorhandler(BusinessException)
def handle_business(e):
return jsonify({"code": e.code, "message": e.message}), 400
@app.errorhandler(ValidationError)
def handle_validation(e):
return jsonify({"code": "VALIDATION_ERROR", "message": str(e)}), 400
@app.errorhandler(404)
def not_found(e):
return jsonify({"code": "NOT_FOUND", "message": "资源不存在"}), 404
# FastAPI 更简洁
from fastapi import HTTPException
@app.get("/users/{user_id}")
async def get_user(user_id: int):
user = find_user(user_id)
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
return user
八、测试对比
8.1 Spring Boot测试
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
public void testGetUser() throws Exception {
when(userService.findById(1L))
.thenReturn(new User("Alice", "alice@example.com"));
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Alice"))
.andExpect(jsonPath("$.email").value("alice@example.com"));
}
}
8.2 Flask测试
import pytest
from flask import Flask
@pytest.fixture
def app():
app = Flask(__name__)
app.config["TESTING"] = True
@app.route("/users/<int:user_id>")
def get_user(user_id):
user = user_service.find_by_id(user_id)
return jsonify(user)
return app
@pytest.fixture
def client(app):
return app.test_client()
def test_get_user(monkeypatch):
def mock_find_by_id(user_id):
return {"id": user_id, "name": "Alice", "email": "alice@example.com"}
monkeypatch.setattr(user_service, "find_by_id", mock_find_by_id)
response = client.get("/users/1")
assert response.status_code == 200
assert response.json["name"] == "Alice"
九、项目结构最佳实践
9.1 Java vs Python项目结构对比
// Java Spring Boot 标准结构
my-spring-project/
├── pom.xml # Maven配置
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/demo/
│ │ │ ├── DemoApplication.java # 启动类
│ │ │ ├── controller/ # 控制器
│ │ │ ├── service/ # 服务层
│ │ │ ├── repository/ # 数据访问
│ │ │ ├── entity/ # 实体类
│ │ │ ├── dto/ # 数据传输对象
│ │ │ ├── config/ # 配置类
│ │ │ └── exception/ # 异常处理
│ │ └── resources/
│ │ ├── application.yml # 配置文件
│ │ └── static/ # 静态资源
│ └── test/
│ └── java/
└── README.md
# Python FastAPI 标准结构(推荐)
my-fastapi-project/
├── pyproject.toml # 项目配置(现代标准)
├── requirements.txt # 依赖列表(兼容)
├── README.md
├── .env.example # 环境变量示例
├── .gitignore
├── src/ # 源代码目录
│ └── myapp/
│ ├── __init__.py
│ ├── main.py # 入口文件
│ ├── core/ # 核心配置
│ │ ├── __init__.py
│ │ ├── config.py # 配置管理
│ │ ├── security.py # 安全相关
│ │ └── dependencies.py # 依赖注入
│ ├── api/ # API层
│ │ ├── __init__.py
│ │ ├── deps.py # API依赖
│ │ └── v1/ # API版本
│ │ ├── __init__.py
│ │ ├── endpoints/
│ │ │ ├── __init__.py
│ │ │ ├── users.py
│ │ │ └── auth.py
│ │ └── router.py
│ ├── models/ # 数据模型
│ │ ├── __init__.py
│ │ └── user.py
│ ├── schemas/ # Pydantic模型
│ │ ├── __init__.py
│ │ └── user.py
│ ├── services/ # 业务逻辑
│ │ ├── __init__.py
│ │ └── user_service.py
│ ├── repositories/ # 数据访问
│ │ ├── __init__.py
│ │ └── user_repo.py
│ └── utils/ # 工具函数
│ ├── __init__.py
│ └── helpers.py
├── tests/ # 测试目录
│ ├── __init__.py
│ ├── conftest.py # pytest配置
│ └── test_users.py
└── alembic/ # 数据库迁移
└── versions/
9.2 三种框架的项目结构对比
Flask 项目结构
# Flask 小型项目
flask-app/
├── app.py # 单文件应用(适合小型项目)
├── requirements.txt
└── templates/
└── index.html
# Flask 中大型项目(推荐)
flask-app/
├── wsgi.py # WSGI入口
├── app/
│ ├── __init__.py # 创建Flask应用
│ ├── extensions.py # 扩展初始化
│ ├── config.py # 配置
│ ├── models/
│ │ ├── __init__.py
│ │ └── user.py
│ ├── routes/
│ │ ├── __init__.py
│ │ └── user_routes.py
│ ├── services/
│ │ └── user_service.py
│ ├── templates/
│ └── static/
├── migrations/
├── tests/
└── requirements.txt
Django 项目结构
# Django 项目结构
django-project/
├── manage.py
├── config/ # 项目配置
│ ├── __init__.py
│ ├── settings/
│ │ ├── __init__.py
│ │ ├── base.py # 基础配置
│ │ ├── development.py # 开发环境
│ │ └── production.py # 生产环境
│ ├── urls.py
│ ├── wsgi.py
│ └── asgi.py
├── apps/ # 应用目录
│ ├── users/ # 用户应用
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── views.py
│ │ ├── urls.py
│ │ ├── serializers.py # DRF序列化器
│ │ ├── services.py # 业务逻辑
│ │ └── migrations/
│ └── orders/ # 订单应用
│ └── ...
├── templates/
├── static/
├── media/
├── tests/
└── requirements.txt
FastAPI 项目结构
# FastAPI 项目结构(推荐)
fastapi-project/
├── pyproject.toml # 项目配置
├── src/
│ └── app/
│ ├── __init__.py
│ ├── main.py # FastAPI应用入口
│ ├── api/
│ │ ├── __init__.py
│ │ ├── deps.py # 公共依赖
│ │ └── v1/
│ │ ├── __init__.py
│ │ ├── router.py # 汇总路由
│ │ └── endpoints/
│ │ ├── users.py
│ │ └── items.py
│ ├── core/
│ │ ├── __init__.py
│ │ ├── config.py # 配置
│ │ └── security.py # JWT等
│ ├── models/ # SQLAlchemy模型
│ │ ├── __init__.py
│ │ └── user.py
│ ├── schemas/ # Pydantic模型
│ │ ├── __init__.py
│ │ └── user.py
│ ├── crud/ # CRUD操作
│ │ ├── __init__.py
│ │ └── user.py
│ └── db/
│ ├── __init__.py
│ ├── base.py # Base类
│ └── session.py # 数据库会话
├── tests/
├── alembic/
└── docker-compose.yml
9.3 目录规范详解
命名规范对比
| 类型 | Java | Python |
|---|---|---|
| 包名/模块名 | com.example.userService | user_service |
| 类名 | UserService | UserService |
| 函数名 | getUserById | get_user_by_id |
| 变量名 | userName | user_name |
| 常量 | MAX_SIZE | MAX_SIZE |
| 文件名 | UserService.java | user_service.py |
__init__.py 的作用
# Python的__init__.py文件
# 1. 标识目录为Python包
# 2. 可以导出公共接口
# 3. 可以执行初始化代码
# myapp/__init__.py
from .main import create_app
from .models import User
from .services import UserService
__all__ = ["create_app", "User", "UserService"]
# 使用时可以直接导入
from myapp import User, UserService
配置管理对比
// Java - application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate
# Python - 使用pydantic-settings(推荐)
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "My API"
database_url: str
secret_key: str
debug: bool = False
class Config:
env_file = ".env"
settings = Settings()
# 使用
from app.core.config import settings
print(settings.database_url)
9.4 分层架构对比
// Java Spring Boot 分层
Controller → Service → Repository → Entity
// 典型调用链
UserController
↓
UserService (业务逻辑)
↓
UserRepository (数据访问)
↓
User (实体)
# Python FastAPI 分层(推荐)
Router → Service → Repository → Model
# 典型调用链
users.py (endpoints)
↓
user_service.py (业务逻辑)
↓
user_repo.py (数据访问)
↓
user.py (SQLAlchemy Model)
# schemas/ 用于请求/响应的数据验证
9.5 项目配置文件对比
// Java - pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
# Python - pyproject.toml(现代标准)
[project]
name = "my-api"
version = "1.0.0"
description = "My FastAPI Project"
requires-python = ">=3.10"
dependencies = [
"fastapi>=0.100.0",
"uvicorn>=0.23.0",
"sqlalchemy>=2.0.0",
"pydantic>=2.0.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"black>=23.0.0",
"mypy>=1.0.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
9.6 最佳实践建议
| 实践 | Java | Python |
|---|---|---|
| 配置管理 | application.yml + @Value | pydantic-settings + .env |
| 依赖注入 | Spring IoC容器 | FastAPI Depends() |
| 数据验证 | @Valid + Bean Validation | Pydantic自动验证 |
| 日志 | SLF4J + Logback | logging模块 |
| 测试 | JUnit + Mockito | pytest + pytest-asyncio |
| 代码风格 | Checkstyle/Spotless | Black + Ruff |
| 类型检查 | 编译时检查 | mypy静态检查 |
十、总结与选择建议
| 场景 | 推荐框架 | 理由 |
|---|---|---|
| 微服务/API | Spring Boot + FastAPI | Spring生态 + 异步性能 |
| 快速原型 | Django | 全功能、内置Admin |
| 小型API | Flask | 轻量、灵活 |
| 高性能异步 | FastAPI | async/await、自动文档 |
| 学习Web开发 | Flask | 概念简单、代码少 |
Java工程师的选择建议:
- 如果你做企业级开发 → Django(类Spring的全功能框架)
- 如果你要快速构建REST API → FastAPI(现代、类型安全)
- 如果你做微服务 → Spring Cloud + FastAPI混合
Python Web框架的设计理念是"选择优于约定"。Django给你全部功能,Flask给你基础让你选择,FastAPI给你类型安全。三者各有优势,根据项目需求选择。