【AI】Codex + 后端框架实战:Spring/Express/Django 业务逻辑全自动生成
·
Codex + 后端框架实战:Spring/Express/Django 业务逻辑全自动生成
目标:同一业务需求(电商订单系统),对比三大框架的 AI 生成策略、代码质量和工程化差异。
一、测试基准:统一业务需求
# 需求规格(ARD 格式)
业务: 电商订单核心流程
功能模块:
1. 订单创建: 购物车结算 → 库存预占 → 价格计算 → 订单持久化
2. 订单支付: 支付回调 → 状态机推进 → 库存扣减 → 通知发货
3. 订单查询: 多维度筛选 → 分页 → 关联数据聚合
非功能需求:
- 并发: 库存扣减需乐观锁/分布式锁
- 事务: 创建订单 + 预占库存原子性
- 性能: P99 < 200ms,支持 1万 QPS
- 安全: 防超卖、防重复支付、SQL注入防护
技术约束:
- Java: Spring Boot 3.2 + JPA + Redis
- Node: Express 4 + TypeScript + Prisma
- Python: Django 4.2 + DRF + Celery
二、Spring Boot 实战:企业级 Java 方案
2.1 架构约束定义(人工)
// 架构基类(强制 Codex 遵循)
// domain/aggregate/AggregateRoot.java
public abstract class AggregateRoot<ID> {
private final ID id;
private final List<DomainEvent> domainEvents = new ArrayList<>();
protected void registerEvent(DomainEvent event) {
domainEvents.add(event);
}
public List<DomainEvent> popEvents() {
List<DomainEvent> events = new ArrayList<>(domainEvents);
domainEvents.clear();
return events;
}
}
// application/UseCase.java
public interface UseCase<I, O> {
O execute(I input);
}
// infrastructure/UnitOfWork.java
public interface UnitOfWork {
void commit();
void rollback();
}
2.2 Codex 生成 Prompt
【Spring Boot 业务生成】
已实现:领域基类(AggregateRoot, UseCase, UnitOfWork)
参考范例:src/user/ 模块(已固定上下文)
需求:实现订单创建用例(CreateOrderUseCase)
约束:
1. 必须实现 UseCase<CreateOrderInput, CreateOrderOutput>
2. 领域逻辑在 Order 聚合根内(继承 AggregateRoot)
3. 库存预占使用乐观锁(@Version 或 CAS)
4. 事务边界在 UseCase 层(@Transactional)
5. 发布 OrderCreatedEvent(领域事件)
6. 禁止:Repository 直接返回 Entity,必须转 Domain 对象
验证:
- 代码必须通过 Checkstyle(Google Java Style)
- 必须通过 ArchUnit 架构测试(分层依赖检查)
- 单元测试:正常流程、库存不足、并发冲突
输出:
1. Order 聚合根(实体 + 值对象)
2. CreateOrderUseCase(应用服务)
3. OrderRepository 接口(领域层)+ JPA 实现(基础设施)
4. 单元测试(JUnit 5 + Mockito)
5. 架构合规说明文档
2.3 Codex 生成结果
// ============== Domain Layer ==============
// domain/vo/Money.java
public record Money(
@NotNull BigDecimal amount,
@NotNull Currency currency
) implements Serializable {
public Money {
if (amount.compareTo(BigDecimal.ZERO) < 0) {
throw new DomainException("金额不能为负");
}
}
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new DomainException("币种不匹配");
}
return new Money(this.amount.add(other.amount), this.currency);
}
public static Money zero(Currency currency) {
return new Money(BigDecimal.ZERO, currency);
}
}
// domain/entity/OrderItem.java
@Entity
@Table(name = "order_items")
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;
@Column(name = "product_id", nullable = false)
private Long productId;
@Embedded
private Money unitPrice;
@Column(name = "quantity", nullable = false)
private Integer quantity;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "amount", column = @Column(name = "subtotal_amount")),
@AttributeOverride(name = "currency", column = @Column(name = "subtotal_currency"))
})
private Money subtotal;
protected OrderItem() {} // JPA 需要
public OrderItem(Long productId, Money unitPrice, Integer quantity) {
this.productId = productId;
this.unitPrice = unitPrice;
this.quantity = quantity;
this.subtotal = unitPrice.amount()
.multiply(BigDecimal.valueOf(quantity))
.pipe(a -> new Money(a, unitPrice.currency()));
}
// Getters...
}
// domain/aggregate/Order.java
@Entity
@Table(name = "orders")
public class Order extends AggregateRoot<Long> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id", nullable = false)
private Long userId;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "amount", column = @Column(name = "total_amount")),
@AttributeOverride(name = "currency", column = @Column(name = "total_currency"))
})
private Money totalAmount;
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
private OrderStatus status;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Version
private Long version; // 乐观锁
protected Order() {
super(null);
}
// 工厂方法:创建订单(领域逻辑核心)
public static Order create(Long userId, List<OrderItem> items) {
if (items == null || items.isEmpty()) {
throw new DomainException("订单不能为空");
}
Order order = new Order();
order.userId = userId;
order.items = items;
order.status = OrderStatus.CREATED;
order.createdAt = LocalDateTime.now();
// 计算总价
order.totalAmount = items.stream()
.map(OrderItem::getSubtotal)
.reduce(Money.zero(Currency.CNY), Money::add);
// 关联双向关系
items.forEach(item -> item.setOrder(order));
// 注册领域事件
order.registerEvent(new OrderCreatedEvent(
order.id,
order.userId,
order.totalAmount,
order.createdAt
));
return order;
}
// 支付成功:状态机推进
public void pay(Money paidAmount) {
if (this.status != OrderStatus.CREATED) {
throw new DomainException("订单状态不正确,当前: " + this.status);
}
if (!this.totalAmount.amount().equals(paidAmount.amount())) {
throw new DomainException("支付金额不匹配");
}
this.status = OrderStatus.PAID;
registerEvent(new OrderPaidEvent(this.id, paidAmount, LocalDateTime.now()));
}
// Getters...
}
// ============== Application Layer ==============
// application/dto/CreateOrderInput.java
public record CreateOrderInput(
@NotNull Long userId,
@NotEmpty List<CartItem> cartItems
) {
public record CartItem(
@NotNull Long productId,
@NotNull @Positive Integer quantity
) {}
}
// application/dto/CreateOrderOutput.java
public record CreateOrderOutput(
Long orderId,
Money totalAmount,
OrderStatus status,
LocalDateTime createdAt
) {}
// application/usecase/CreateOrderUseCase.java
@Service
@RequiredArgsConstructor
@Transactional(isolation = Isolation.READ_COMMITTED)
public class CreateOrderUseCase implements UseCase<CreateOrderInput, CreateOrderOutput> {
private final OrderRepository orderRepository;
private final InventoryService inventoryService; // 防腐层接口
private final PricingService pricingService;
private final DomainEventPublisher eventPublisher;
@Override
public CreateOrderOutput execute(CreateOrderInput input) {
// 1. 库存预占(带乐观锁)
List<InventoryReservation> reservations = new ArrayList<>();
for (var cartItem : input.cartItems()) {
var reservation = inventoryService.reserve(
cartItem.productId(),
cartItem.quantity()
);
reservations.add(reservation);
}
try {
// 2. 获取商品价格
List<OrderItem> orderItems = new ArrayList<>();
for (int i = 0; i < input.cartItems().size(); i++) {
var cartItem = input.cartItems().get(i);
var price = pricingService.getPrice(cartItem.productId());
orderItems.add(new OrderItem(
cartItem.productId(),
price,
cartItem.quantity()
));
}
// 3. 创建订单(领域逻辑)
Order order = Order.create(input.userId(), orderItems);
// 4. 持久化
Order savedOrder = orderRepository.save(order);
// 5. 发布领域事件
order.popEvents().forEach(eventPublisher::publish);
// 6. 确认库存预占
reservations.forEach(r -> inventoryService.confirm(r.id()));
return new CreateOrderOutput(
savedOrder.getId(),
savedOrder.getTotalAmount(),
savedOrder.getStatus(),
savedOrder.getCreatedAt()
);
} catch (Exception e) {
// 回滚库存预占
reservations.forEach(r -> inventoryService.cancel(r.id()));
throw e;
}
}
}
// ============== Infrastructure Layer ==============
// infrastructure/persistence/JpaOrderRepository.java
@Repository
@RequiredArgsConstructor
public class JpaOrderRepository implements OrderRepository {
private final SpringDataOrderRepository jpaRepository;
private final OrderJpaMapper mapper;
@Override
public Optional<Order> findById(Long id) {
return jpaRepository.findById(id)
.map(mapper::toDomain);
}
@Override
public Order save(Order order) {
OrderJpaEntity entity = mapper.toEntity(order);
OrderJpaEntity saved = jpaRepository.save(entity);
return mapper.toDomain(saved);
}
}
// infrastructure/messaging/SpringEventPublisher.java
@Component
@RequiredArgsConstructor
public class SpringEventPublisher implements DomainEventPublisher {
private final ApplicationEventPublisher publisher;
@Override
public void publish(DomainEvent event) {
publisher.publishEvent(event);
}
}
// ============== Test ==============
@SpringBootTest
@Transactional
class CreateOrderUseCaseTest {
@Autowired
private CreateOrderUseCase useCase;
@MockBean
private InventoryService inventoryService;
@MockBean
private PricingService pricingService;
@Test
@DisplayName("正常创建订单")
void execute_Success() {
// Given
when(inventoryService.reserve(any(), any()))
.thenReturn(new InventoryReservation(1L, 100L, 2));
when(pricingService.getPrice(100L))
.thenReturn(new Money(new BigDecimal("99.99"), Currency.CNY));
var input = new CreateOrderInput(
1L,
List.of(new CreateOrderInput.CartItem(100L, 2))
);
// When
var output = useCase.execute(input);
// Then
assertThat(output.orderId()).isNotNull();
assertThat(output.totalAmount().amount())
.isEqualByComparingTo(new BigDecimal("199.98"));
assertThat(output.status()).isEqualTo(OrderStatus.CREATED);
verify(inventoryService).confirm(1L);
}
@Test
@DisplayName("库存不足,抛出异常并回滚预占")
void execute_InsufficientInventory() {
when(inventoryService.reserve(any(), any()))
.thenThrow(new InsufficientInventoryException("库存不足"));
assertThatThrownBy(() -> useCase.execute(any()))
.isInstanceOf(InsufficientInventoryException.class);
}
}
2.4 Spring 生成质量评估
| 维度 | 评分 | 说明 |
|---|---|---|
| 架构合规 | 9/10 | 严格遵循 DDD 分层,依赖方向正确 |
| 类型安全 | 10/10 | 泛型、Record、@NotNull 完整 |
| 事务处理 | 8/10 | 手动回滚库存需优化为 Saga 模式 |
| 并发控制 | 7/10 | 乐观锁在 Order,但库存需分布式锁 |
| 测试覆盖 | 9/10 | 正常+异常路径覆盖,需补充并发测试 |
| 代码量 | 300+ 行 | 偏冗长,但符合 Java 企业级习惯 |
三、Express + TypeScript 实战:轻量全栈方案
3.1 架构约束定义(人工)
// 架构基类
// core/UseCase.ts
export interface UseCase<Input, Output> {
execute(input: Input): Promise<Output>;
}
// core/Result.ts(函数式错误处理)
export type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
// core/DomainEvent.ts
export interface DomainEvent {
readonly occurredOn: Date;
readonly eventType: string;
}
3.2 Codex 生成 Prompt
【Express + TypeScript 业务生成】
已实现:核心基类(UseCase, Result, DomainEvent)
参考范例:src/modules/user/(函数式风格,禁止 class 过多)
需求:实现订单创建用例
约束:
1. 使用函数式编程风格(优先函数/接口,class 仅用于聚合根)
2. 错误处理使用 Result 类型,禁止 throw
3. 异步使用 async/await,禁止回调
4. 数据库使用 Prisma,禁止原生 SQL
5. 库存预占使用 Redis 分布式锁(Redlock)
6. 发布事件到 Redis Pub/Sub(解耦)
验证:
- ESLint(@typescript-eslint/recommended)
- 类型检查(strict 模式零错误)
- 测试:Jest + 内存数据库(sqlite)
输出:
1. 领域层(函数 + 类型定义)
2. 应用层(UseCase 实现)
3. 基础设施(Prisma schema + Repository 实现)
4. API 层(Express Route + Controller)
5. 完整测试(集成测试覆盖数据库操作)
3.3 Codex 生成结果
// ============== Domain Layer ==============
// domain/order/types.ts
export type OrderId = string & { readonly __brand: 'OrderId' };
export type UserId = string & { readonly __brand: 'UserId' };
export type ProductId = string & { readonly __brand: 'ProductId' };
export interface Money {
readonly amount: number;
readonly currency: 'CNY' | 'USD';
}
export const Money = {
create(amount: number, currency: Money['currency']): Result<Money> {
if (amount < 0) {
return { success: false, error: new Error('金额不能为负') };
}
return { success: true, data: { amount, currency } };
},
add(a: Money, b: Money): Result<Money> {
if (a.currency !== b.currency) {
return { success: false, error: new Error('币种不匹配') };
}
return Money.create(a.amount + b.amount, a.currency);
},
zero(currency: Money['currency']): Money {
return { amount: 0, currency };
}
};
export enum OrderStatus {
CREATED = 'CREATED',
PAID = 'PAID',
SHIPPED = 'SHIPPED',
COMPLETED = 'COMPLETED',
CANCELLED = 'CANCELLED'
}
export interface OrderItem {
readonly productId: ProductId;
readonly unitPrice: Money;
readonly quantity: number;
readonly subtotal: Money;
}
export const OrderItem = {
create(
productId: ProductId,
unitPrice: Money,
quantity: number
): Result<OrderItem> {
if (quantity <= 0) {
return { success: false, error: new Error('数量必须为正') };
}
const subtotalResult = Money.create(
unitPrice.amount * quantity,
unitPrice.currency
);
if (!subtotalResult.success) {
return subtotalResult;
}
return {
success: true,
data: {
productId,
unitPrice,
quantity,
subtotal: subtotalResult.data
}
};
}
};
export interface Order {
readonly id: OrderId;
readonly userId: UserId;
readonly items: readonly OrderItem[];
readonly totalAmount: Money;
readonly status: OrderStatus;
readonly createdAt: Date;
readonly domainEvents: readonly DomainEvent[];
}
// 领域事件
export interface OrderCreatedEvent extends DomainEvent {
readonly type: 'OrderCreated';
readonly orderId: OrderId;
readonly userId: UserId;
readonly totalAmount: Money;
}
// ============== Domain Functions ==============
// domain/order/order.ts
import { v4 as uuidv4 } from 'uuid';
export const Order = {
create(
userId: UserId,
items: OrderItem[]
): Result<Order & { popEvents(): DomainEvent[] }> {
if (items.length === 0) {
return { success: false, error: new Error('订单不能为空') };
}
// 计算总价
const totalResult = items.reduce<Result<Money>>(
(acc, item) => {
if (!acc.success) return acc;
return Money.add(acc.data, item.subtotal);
},
{ success: true, data: Money.zero('CNY') }
);
if (!totalResult.success) {
return totalResult;
}
const id = uuidv4() as OrderId;
const event: OrderCreatedEvent = {
type: 'OrderCreated',
occurredOn: new Date(),
orderId: id,
userId,
totalAmount: totalResult.data
};
let events: DomainEvent[] = [event];
const order: Order & { popEvents(): DomainEvent[] } = {
id,
userId,
items: Object.freeze([...items]),
totalAmount: totalResult.data,
status: OrderStatus.CREATED,
createdAt: new Date(),
get domainEvents() { return Object.freeze([...events]); },
popEvents() {
const popped = [...events];
events = [];
return popped;
}
};
return { success: true, data: order };
}
};
// ============== Application Layer ==============
// application/order/CreateOrderUseCase.ts
import { UseCase } from '../../core/UseCase';
import { Result } from '../../core/Result';
import { DomainEventPublisher } from '../../core/DomainEventPublisher';
import { OrderRepository } from '../../domain/order/OrderRepository';
import { InventoryService } from '../../domain/inventory/InventoryService';
import { PricingService } from '../../domain/pricing/PricingService';
import { Order, OrderItem, Money } from '../../domain/order';
import { LockService } from '../../infrastructure/lock/LockService';
export interface CreateOrderInput {
readonly userId: string;
readonly cartItems: ReadonlyArray<{
readonly productId: string;
readonly quantity: number;
}>;
}
export interface CreateOrderOutput {
readonly orderId: string;
readonly totalAmount: number;
readonly currency: string;
readonly status: string;
}
export class CreateOrderUseCase implements UseCase<CreateOrderInput, CreateOrderOutput> {
constructor(
private readonly orderRepo: OrderRepository,
private readonly inventoryService: InventoryService,
private readonly pricingService: PricingService,
private readonly eventPublisher: DomainEventPublisher,
private readonly lockService: LockService
) {}
async execute(input: CreateOrderInput): Promise<Result<CreateOrderOutput>> {
const lockKeys = input.cartItems.map(item => `inventory:${item.productId}`);
// 获取分布式锁(防止超卖)
const lockResult = await this.lockService.acquire(lockKeys, 5000);
if (!lockResult.success) {
return { success: false, error: new Error('系统繁忙,请重试') };
}
const reservations: string[] = [];
try {
// 1. 库存预占
for (const item of input.cartItems) {
const reserveResult = await this.inventoryService.reserve(
item.productId as ProductId,
item.quantity
);
if (!reserveResult.success) {
return reserveResult;
}
reservations.push(reserveResult.data.reservationId);
}
// 2. 构建订单项
const orderItems: OrderItem[] = [];
for (const item of input.cartItems) {
const priceResult = await this.pricingService.getPrice(item.productId as ProductId);
if (!priceResult.success) {
return priceResult;
}
const itemResult = OrderItem.create(
item.productId as ProductId,
priceResult.data,
item.quantity
);
if (!itemResult.success) {
return itemResult;
}
orderItems.push(itemResult.data);
}
// 3. 创建订单
const orderResult = Order.create(input.userId as UserId, orderItems);
if (!orderResult.success) {
return orderResult;
}
const order = orderResult.data;
// 4. 持久化
const saveResult = await this.orderRepo.save(order);
if (!saveResult.success) {
return saveResult;
}
// 5. 发布事件
const events = order.popEvents();
for (const event of events) {
await this.eventPublisher.publish(event);
}
// 6. 确认库存
for (const reservationId of reservations) {
await this.inventoryService.confirm(reservationId);
}
return {
success: true,
data: {
orderId: order.id,
totalAmount: order.totalAmount.amount,
currency: order.totalAmount.currency,
status: order.status
}
};
} catch (error) {
// 回滚库存
for (const reservationId of reservations) {
await this.inventoryService.cancel(reservationId).catch(() => {});
}
return {
success: false,
error: error instanceof Error ? error : new Error(String(error))
};
} finally {
await this.lockService.release(lockResult.data);
}
}
}
// ============== Infrastructure Layer ==============
// infrastructure/persistence/prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Order {
id String @id @default(uuid())
userId String
status String
totalAmount Decimal @db.Decimal(19, 4)
currency String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
items OrderItem[]
@@index([userId])
@@index([status, createdAt])
}
model OrderItem {
id String @id @default(uuid())
orderId String
productId String
unitPrice Decimal @db.Decimal(19, 4)
quantity Int
subtotal Decimal @db.Decimal(19, 4)
order Order @relation(fields: [orderId], references: [id])
@@index([productId])
}
// infrastructure/persistence/PrismaOrderRepository.ts
import { PrismaClient } from '@prisma/client';
import { OrderRepository } from '../../domain/order/OrderRepository';
import { Order, OrderItem, OrderStatus, Money } from '../../domain/order';
import { Result } from '../../core/Result';
export class PrismaOrderRepository implements OrderRepository {
constructor(private readonly prisma: PrismaClient) {}
async save(order: Order): Promise<Result<Order>> {
try {
const created = await this.prisma.order.create({
data: {
id: order.id,
userId: order.userId,
status: order.status,
totalAmount: order.totalAmount.amount,
currency: order.totalAmount.currency,
items: {
create: order.items.map(item => ({
productId: item.productId,
unitPrice: item.unitPrice.amount,
quantity: item.quantity,
subtotal: item.subtotal.amount
}))
}
},
include: { items: true }
});
return { success: true, data: order };
} catch (error) {
return {
success: false,
error: new Error(`保存订单失败: ${error}`)
};
}
}
// ... findById 等
}
// ============== API Layer ==============
// api/routes/orderRoutes.ts
import { Router } from 'express';
import { CreateOrderUseCase } from '../../application/order/CreateOrderUseCase';
import { body, validationResult } from 'express-validator';
export const createOrderRouter = (
createOrderUseCase: CreateOrderUseCase
): Router => {
const router = Router();
router.post(
'/orders',
[
body('userId').isUUID(),
body('cartItems').isArray({ min: 1 }),
body('cartItems.*.productId').isUUID(),
body('cartItems.*.quantity').isInt({ min: 1 })
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const result = await createOrderUseCase.execute(req.body);
if (!result.success) {
return res.status(400).json({ error: result.error.message });
}
res.status(201).json(result.data);
}
);
return router;
};
// ============== Test ==============
// tests/integration/CreateOrder.test.ts
import { CreateOrderUseCase } from '../../application/order/CreateOrderUseCase';
import { PrismaOrderRepository } from '../../infrastructure/persistence/PrismaOrderRepository';
import { MockInventoryService } from '../mocks/MockInventoryService';
import { MockPricingService } from '../mocks/MockPricingService';
import { MockEventPublisher } from '../mocks/MockEventPublisher';
import { MockLockService } from '../mocks/MockLockService';
import { PrismaClient } from '@prisma/client';
describe('CreateOrderUseCase Integration', () => {
let prisma: PrismaClient;
let useCase: CreateOrderUseCase;
beforeAll(async () => {
prisma = new PrismaClient({
datasources: { db: { url: 'file:./test.db' } } // SQLite 内存
});
await prisma.$connect();
const repo = new PrismaOrderRepository(prisma);
useCase = new CreateOrderUseCase(
repo,
new MockInventoryService(), // 总是成功
new MockPricingService({ 'prod-1': 99.99 }),
new MockEventPublisher(),
new MockLockService() // 总是获取锁
);
});
afterAll(async () => {
await prisma.$disconnect();
});
it('should create order successfully', async () => {
const result = await useCase.execute({
userId: 'user-1',
cartItems: [{ productId: 'prod-1', quantity: 2 }]
});
expect(result.success).toBe(true);
if (result.success) {
expect(result.data.totalAmount).toBe(199.98);
expect(result.data.status).toBe('CREATED');
}
});
it('should handle insufficient inventory', async () => {
// 模拟库存不足...
});
});
3.4 Express 生成质量评估
| 维度 | 评分 | 说明 |
|---|---|---|
| 架构合规 | 9/10 | 函数式风格,依赖注入清晰 |
| 类型安全 | 10/10 | branded type 防 ID 混用,Result 强制错误处理 |
| 代码简洁 | 9/10 | 200+ 行,比 Spring 少 30% |
| 异步处理 | 9/10 | async/await 贯穿,无回调地狱 |
| 测试友好 | 8/10 | 依赖注入便于 mock,但需手动管理 Prisma 生命周期 |
| 运行时安全 | 7/10 | 无编译期保证,依赖运行时检查 |
四、Django + DRF 实战:快速交付方案
4.1 架构约束定义(人工)
# 架构规范(Django 约定优于配置)
# core/models.py
from django.db import models
class TimestampedModel(models.Model):
"""抽象基类:自动添加创建/更新时间"""
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class DomainEventMixin(models.Model):
"""领域事件支持"""
class Meta:
abstract = True
def save(self, *args, **kwargs):
is_new = self.pk is None
super().save(*args, **kwargs)
if is_new:
self._publish_created_event()
def _publish_created_event(self):
raise NotImplementedError
4.2 Codex 生成 Prompt
【Django + DRF 业务生成】
已实现:TimestampedModel, DomainEventMixin
参考范例:apps/users/(CBV 风格,DRF Serializer)
需求:实现订单创建 API
约束:
1. 模型继承 TimestampedModel,使用 Django ORM(禁止原生 SQL)
2. API 使用 DRF ModelSerializer + ModelViewSet
3. 业务逻辑在 Serializer 或 Service 层,禁止在 View 中写逻辑
4. 库存预占使用 select_for_update()(数据库锁)
5. 异步任务使用 Celery(发送通知、更新统计)
6. 单元测试使用 Django TestCase + factory_boy
验证:
- pylint-django 零警告
- 测试覆盖率 >85%
- API 文档自动生成(drf-spectacular)
输出:
1. models.py(Order, OrderItem)
2. serializers.py(创建 + 查询)
3. views.py(ModelViewSet + 自定义 action)
4. services.py(复杂业务逻辑)
5. tasks.py(Celery 异步任务)
6. tests.py(完整测试)
4.3 Codex 生成结果
# ============== Models ==============
# apps/orders/models.py
from django.db import models, transaction
from django.core.validators import MinValueValidator
from django.core.exceptions import ValidationError
from apps.core.models import TimestampedModel, DomainEventMixin
from apps.products.models import Product # 假设已存在
class OrderStatus(models.TextChoices):
CREATED = 'created', '待支付'
PAID = 'paid', '已支付'
SHIPPED = 'shipped', '已发货'
COMPLETED = 'completed', '已完成'
CANCELLED = 'cancelled', '已取消'
class Order(TimestampedModel, DomainEventMixin):
"""订单聚合根"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(
'users.User',
on_delete=models.PROTECT,
related_name='orders',
verbose_name='用户'
)
status = models.CharField(
max_length=20,
choices=OrderStatus.choices,
default=OrderStatus.CREATED,
verbose_name='状态'
)
total_amount = models.DecimalField(
max_digits=19,
decimal_places=2,
default=0,
verbose_name='总金额'
)
currency = models.CharField(max_length=3, default='CNY', verbose_name='币种')
paid_at = models.DateTimeField(null=True, blank=True, verbose_name='支付时间')
class Meta:
db_table = 'orders'
ordering = ['-created_at']
indexes = [
models.Index(fields=['user', '-created_at']),
models.Index(fields=['status', 'created_at']),
]
def clean(self):
if self.paid_at and self.status != OrderStatus.PAID:
raise ValidationError('支付时间仅在已支付状态允许')
def calculate_total(self):
"""计算订单总价"""
self.total_amount = sum(
item.subtotal for item in self.items.all()
)
self.save(update_fields=['total_amount', 'updated_at'])
def _publish_created_event(self):
"""发布订单创建事件(Celery 异步处理)"""
from .tasks import notify_order_created
notify_order_created.delay(str(self.id), str(self.user_id))
def __str__(self):
return f'订单 {self.id} ({self.get_status_display()})'
class OrderItem(TimestampedModel):
"""订单项(值对象)"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
order = models.ForeignKey(
Order,
on_delete=models.CASCADE,
related_name='items',
verbose_name='订单'
)
product = models.ForeignKey(
Product,
on_delete=models.PROTECT,
verbose_name='商品'
)
product_name = models.CharField(max_length=255, verbose_name='商品名称快照')
unit_price = models.DecimalField(
max_digits=19,
decimal_places=2,
verbose_name='单价'
)
quantity = models.PositiveIntegerField(
validators=[MinValueValidator(1)],
verbose_name='数量'
)
subtotal = models.DecimalField(
max_digits=19,
decimal_places=2,
verbose_name='小计'
)
class Meta:
db_table = 'order_items'
def save(self, *args, **kwargs):
# 自动计算小计
self.subtotal = self.unit_price * self.quantity
super().save(*args, **kwargs)
def clean(self):
# 库存检查(悲观锁)
with transaction.atomic():
product = Product.objects.select_for_update().get(pk=self.product_id)
if product.stock < self.quantity:
raise ValidationError(
f'商品 {product.name} 库存不足,剩余 {product.stock}'
)
# ============== Services ==============
# apps/orders/services.py
from django.db import transaction
from django.core.exceptions import ValidationError
from .models import Order, OrderItem, OrderStatus
from apps.inventory.services import InventoryService # 防腐层
class OrderService:
"""订单应用服务"""
def __init__(self):
self.inventory_service = InventoryService()
@transaction.atomic
def create_order(self, user, cart_items: list[dict]) -> Order:
"""
创建订单(核心事务)
Args:
user: 用户实例
cart_items: [{'product_id': 'uuid', 'quantity': 2}, ...]
Returns:
Order: 创建的订单
Raises:
ValidationError: 库存不足或参数错误
"""
if not cart_items:
raise ValidationError('购物车不能为空')
# 1. 创建订单(状态:待支付)
order = Order.objects.create(user=user, status=OrderStatus.CREATED)
try:
# 2. 创建订单项(包含库存检查)
for item_data in cart_items:
product_id = item_data['product_id']
quantity = item_data['quantity']
# 预占库存(使用数据库锁防止超卖)
reserved = self.inventory_service.reserve(
product_id=product_id,
quantity=quantity,
order_id=str(order.id)
)
if not reserved:
raise ValidationError(f'商品 {product_id} 库存不足')
# 创建订单项
product = reserved['product'] # 库存服务返回商品信息
OrderItem.objects.create(
order=order,
product=product,
product_name=product.name,
unit_price=product.price,
quantity=quantity
)
# 3. 计算总价
order.calculate_total()
return order
except Exception as e:
# 回滚库存(Celery 异步确保最终一致性)
self.inventory_service.cancel_reservation(order_id=str(order.id))
order.delete()
raise
@transaction.atomic
def pay_order(self, order: Order, payment_amount: float) -> Order:
"""支付订单"""
if order.status != OrderStatus.CREATED:
raise ValidationError('订单状态不允许支付')
if float(order.total_amount) != payment_amount:
raise ValidationError('支付金额不匹配')
# 更新状态
order.status = OrderStatus.PAID
order.paid_at = timezone.now()
order.save()
# 确认库存扣减(异步)
self.inventory_service.confirm_reservation.delay(
order_id=str(order.id)
)
# 触发发货流程(异步)
from .tasks import initiate_shipment
initiate_shipment.delay(str(order.id))
return order
# ============== Serializers ==============
# apps/orders/serializers.py
from rest_framework import serializers
from drf_spectacular.utils import extend_schema_field
from .models import Order, OrderItem
class OrderItemSerializer(serializers.ModelSerializer):
"""订单项序列化器"""
product_id = serializers.UUIDField(source='product.id', read_only=True)
class Meta:
model = OrderItem
fields = ['id', 'product_id', 'product_name', 'unit_price', 'quantity', 'subtotal']
read_only_fields = fields
class CartItemSerializer(serializers.Serializer):
"""购物车项(创建订单输入)"""
product_id = serializers.UUIDField()
quantity = serializers.IntegerField(min_value=1)
class OrderCreateSerializer(serializers.ModelSerializer):
"""创建订单序列化器"""
cart_items = CartItemSerializer(many=True, write_only=True)
class Meta:
model = Order
fields = ['id', 'cart_items', 'total_amount', 'status', 'created_at']
read_only_fields = ['id', 'total_amount', 'status', 'created_at']
def validate_cart_items(self, value):
"""验证购物车非空"""
if not value:
raise serializers.ValidationError('购物车不能为空')
return value
def create(self, validated_data):
"""委托给 Service 层"""
from .services import OrderService
service = OrderService()
cart_items = validated_data.pop('cart_items')
user = self.context['request'].user
return service.create_order(user, cart_items)
class OrderListSerializer(serializers.ModelSerializer):
"""订单列表(精简)"""
item_count = serializers.SerializerMethodField()
class Meta:
model = Order
fields = ['id', 'status', 'total_amount', 'item_count', 'created_at']
@extend_schema_field(serializers.IntegerField())
def get_item_count(self, obj: Order) -> int:
return obj.items.count()
class OrderDetailSerializer(serializers.ModelSerializer):
"""订单详情(完整)"""
items = OrderItemSerializer(many=True, read_only=True)
user_email = serializers.EmailField(source='user.email', read_only=True)
class Meta:
model = Order
fields = [
'id', 'user_email', 'status', 'total_amount', 'currency',
'items', 'created_at', 'updated_at', 'paid_at'
]
# ============== Views ==============
# apps/orders/views.py
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from drf_spectacular.utils import extend_schema, OpenApiParameter
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from .models import Order, OrderStatus
from .serializers import (
OrderCreateSerializer,
OrderListSerializer,
OrderDetailSerializer
)
from .services import OrderService
class OrderViewSet(viewsets.ModelViewSet):
"""
订单管理 API
提供订单的创建、查询、支付等操作
"""
permission_classes = [IsAuthenticated]
lookup_field = 'pk'
def get_queryset(self):
"""用户只能查看自己的订单"""
queryset = Order.objects.filter(user=self.request.user)
# 筛选
status = self.request.query_params.get('status')
if status:
queryset = queryset.filter(status=status)
# 日期范围
date_from = self.request.query_params.get('from')
date_to = self.request.query_params.get('to')
if date_from:
queryset = queryset.filter(created_at__gte=date_from)
if date_to:
queryset = queryset.filter(created_at__lte=date_to)
return queryset.select_related('user').prefetch_related('items')
def get_serializer_class(self):
"""根据动作选择序列化器"""
if self.action == 'create':
return OrderCreateSerializer
elif self.action == 'retrieve':
return OrderDetailSerializer
return OrderListSerializer
@extend_schema(
summary='创建订单',
description='从购物车创建订单,自动检查库存',
request=OrderCreateSerializer,
responses={201: OrderDetailSerializer}
)
def create(self, request, *args, **kwargs):
"""创建订单(重写以使用自定义 Service)"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
order = serializer.save()
# 使用详情序列化器返回
detail_serializer = OrderDetailSerializer(order)
return Response(detail_serializer.data, status=status.HTTP_201_CREATED)
@extend_schema(
summary='支付订单',
description='模拟支付回调,推进订单状态',
request={'application/json': {'payment_amount': 'number'}},
responses={200: OrderDetailSerializer}
)
@action(detail=True, methods=['post'])
def pay(self, request, pk=None):
"""支付订单"""
order = self.get_object()
payment_amount = request.data.get('payment_amount')
if payment_amount is None:
return Response(
{'error': '缺少 payment_amount'},
status=status.HTTP_400_BAD_REQUEST
)
service = OrderService()
try:
paid_order = service.pay_order(order, float(payment_amount))
serializer = OrderDetailSerializer(paid_order)
return Response(serializer.data)
except Exception as e:
return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)
@method_decorator(cache_page(60)) # 缓存1分钟
@extend_schema(
summary='订单统计',
description='获取用户订单统计数据'
)
@action(detail=False, methods=['get'])
def statistics(self, request):
"""订单统计"""
stats = Order.objects.filter(user=request.user).aggregate(
total_orders=models.Count('id'),
total_spent=models.Sum('total_amount'),
pending_payment=models.Count('id', filter=models.Q(status=OrderStatus.CREATED))
)
return Response(stats)
# ============== Celery Tasks ==============
# apps/orders/tasks.py
from celery import shared_task
from django.core.mail import send_mail
from .models import Order
@shared_task(bind=True, max_retries=3)
def notify_order_created(self, order_id: str, user_id: str):
"""异步通知订单创建"""
try:
order = Order.objects.get(id=order_id)
# 发送邮件/短信/推送...
print(f'通知用户 {user_id} 订单 {order_id} 已创建')
except Order.DoesNotExist:
# 重试
raise self.retry(countdown=5)
@shared_task
def initiate_shipment(order_id: str):
"""触发发货流程"""
# 调用物流系统 API...
print(f'开始处理订单 {order_id} 发货')
# ============== Tests ==============
# apps/orders/tests.py
import pytest
from django.test import TestCase
from django.core.exceptions import ValidationError
from rest_framework.test import APIClient
from rest_framework import status
import factory
from .models import Order, OrderItem, OrderStatus
from apps.products.models import Product
from apps.users.models import User
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User
email = factory.Sequence(lambda n: f'user{n}@test.com')
class ProductFactory(factory.django.DjangoModelFactory):
class Meta:
model = Product
name = factory.Sequence(lambda n: f'Product {n}')
price = 99.99
stock = 100
class OrderTestCase(TestCase):
"""订单业务测试"""
def setUp(self):
self.user = UserFactory()
self.product = ProductFactory(stock=10)
self.client = APIClient()
self.client.force_authenticate(user=self.user)
def test_create_order_success(self):
"""正常创建订单"""
response = self.client.post('/api/orders/', {
'cart_items': [{
'product_id': str(self.product.id),
'quantity': 2
}]
}, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['status'], 'created')
self.assertEqual(float(response.data['total_amount']), 199.98)
# 验证库存预占
self.product.refresh_from_db()
self.assertEqual(self.product.stock, 8) # 10 - 2
def test_create_order_insufficient_stock(self):
"""库存不足"""
response = self.client.post('/api/orders/', {
'cart_items': [{
'product_id': str(self.product.id),
'quantity': 999
}]
}, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_pay_order_success(self):
"""正常支付"""
# 先创建订单
order_response = self.client.post('/api/orders/', {
'cart_items': [{'product_id': str(self.product.id), 'quantity': 1}]
}, format='json')
order_id = order_response.data['id']
# 支付
pay_response = self.client.post(
f'/api/orders/{order_id}/pay/',
{'payment_amount': 99.99},
format='json'
)
self.assertEqual(pay_response.status_code, status.HTTP_200_OK)
self.assertEqual(pay_response.data['status'], 'paid')
4.4 Django 生成质量评估
| 维度 | 评分 | 说明 |
|---|---|---|
| 开发速度 | 10/10 | 约定优于配置,代码量最少(150+ 行) |
| 功能完整 | 9/10 | ORM + Admin + 缓存 + 异步一站式 |
| 可维护性 | 8/10 | 强约定降低自由度,但团队协作友好 |
| 性能优化 | 7/10 | ORM 隐藏查询细节,需手动优化 N+1 |
| 类型安全 | 6/10 | Python 动态类型,依赖运行时检查 |
| 扩展性 | 7/10 | 单体友好,微服务拆分成本较高 |
五、三大框架横评总结
| 维度 | Spring Boot | Express/TS | Django |
|---|---|---|---|
| 代码量 | 300+ 行 | 200+ 行 | 150+ 行 |
| 生成速度 | 慢(需处理大量样板) | 中 | 快(约定驱动) |
| 类型安全 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐☆☆ |
| 架构灵活 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐☆☆ |
| 企业级功能 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐☆☆ | ⭐⭐⭐⭐☆ |
| 团队约束 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ |
| AI 可控性 | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
选择策略
企业级复杂系统(金融、电信)→ Spring Boot
└── 严格分层、事务、监控、合规
现代全栈应用(SaaS、API 服务)→ Express + TypeScript
└── 快速迭代、类型安全、前后端统一语言
快速 MVP、内容驱动产品 → Django
└── 极速交付、内置功能丰富、维护成本低
六、通用最佳实践:跨框架的 AI 生成策略
1. 分层生成(降低单次复杂度)
Step 1: 生成领域模型(实体 + 值对象 + 领域事件)
↓ 人工审查:业务规则是否正确
Step 2: 生成应用服务(用例编排)
↓ 人工审查:事务边界、依赖方向
Step 3: 生成基础设施(仓储、外部服务)
↓ 人工审查:技术选型、性能陷阱
Step 4: 生成接口层(API + 测试)
↓ 人工审查:安全、文档、边界测试
2. 约束即代码(强制规范)
# 架构测试(ArchUnit / 自定义脚本)
def test_layer_dependencies():
"""禁止跨层调用"""
# 领域层不依赖其他层
assert not imports_from("domain", "application")
assert not imports_from("domain", "infrastructure")
# 应用层仅依赖领域层
assert not imports_from("application", "infrastructure")
3. 契约驱动(API 优先)
# OpenAPI 规范(人工定义)
openapi: 3.0.0
paths:
/orders:
post:
summary: 创建订单
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CreateOrderRequest'
responses:
201:
content:
application/json:
schema:
$ref: '#/components/schemas/OrderResponse'
# Codex 任务:实现此契约,禁止偏离
七、一句话总结
框架选择决定下限,AI 约束决定上限。Spring 适合"规范重"的企业,Express 适合"灵活快"的初创,Django 适合"交付快"的 MVP——但无论选哪个,给 Codex 的约束越清晰,生成的代码越生产级。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)