
为什么 Cursor 生成的代码总不符合你的习惯?试试这几种方法 原创
目前团队研发已全面采用Cursor作为主力工具。虽然Claude Code和Argument Code在功能上更胜一筹,但考虑到成本因素和网络问题,Cursor仍是我们的首选。然而我们发现,尽管使用相同的工具,团队成员的工作效率和体验却存在显著差异——关键在于对Cursor的掌握程度。本文将分享日常工作中的最佳实践,帮助大家充分发挥Cursor的潜力。
cursor开发全流程
要让 Cursor 充分发挥其潜力,达到我们的预期效果,需要系统性地结合以下四个关键要素:
- 精准的提示词
- 合理且规范的开发流程
- 好用的cursorrules
- 好用的mcp工具
只有这四个方面协同优化,才能让 Cursor 真正成为高效的生产力工具,而不仅仅是一个普通的代码编辑器。
prompt
不得不说,Prompt Enginer是 AI 时代入门的必备技能。一个好的提示词能让 Cursor 更精准地理解需求,输出更符合预期的代码。我们通常将提示词分为三个核心部分:
- 目标描述(What)—— 明确你要实现什么
- 上下文信息(Why & Background)—— 提供必要的背景,帮助 AI 理解场景
- 具体要求(How)—— 定义输出格式、约束条件等
下面给出一些不同阶段的提示词示例:
项目梳理
# Objective
Please conduct an in-depth analysis of the current codebase and generate a project overview document.
# Requirements
The project review document you generate must be produced strictly in accordance with the "Project Document Organization Standards" in the project rules.
# output
Please output the project organization document and place it in the appropriate location of the project.
技术方案
当我们有了需求文档之后,我们就可让cursor基于需求文档、已有的代码(如果有的话)和上一步项目梳理的代码来进一步生成技术架构方案。
# Goal
Please generate the technical solution based on the requirements document. Note that you only need to output the detailed technical solution document. At this stage, there is no need to modify the code. At this point, the requirements document has been placed in our project in the form of a document.
# Background Knowledge
To help you generate the technical solution better, I have provided you with:
(1) Project code
(2) Requirements Document: "XX.md" s
(3) Project understanding document: "XX.md"
# Core Tasks
## 1. Document Analysis and Understanding stage
Complete the following analysis before finishing the scheme design:
- Understand the requirements in detail:
Please confirm that you have deeply understood all the requirement descriptions and functional changes mentioned in "Requirement.md".
If there are any points you don't understand or find any contradictions, please mark them immediately and submit a note.
- Understanding of code architecture:
Gain a thorough understanding of the project's documentation and the hierarchical structure of the existing code base, and determine the insertion positions for new features.
List the reusable utility classes, exception handling mechanisms and common interfaces (such as the 'utils.py' and 'ErrorCode' enumeration classes).
## 2. Scheme design stage
Please design a detailed solution based on the requirements and place the generated technical solution in the project docs directory. No code generation is required at this stage.
# Requirement
The technical solution you generate must be strictly produced in accordance with the "Technical Solution Design Document Specification" in the project rules and conform to the technical solution design document template.
# Output
Please output the technical solution and place the generated technical solution in the appropriate position of the project. There is no need to generate code.
代码落地
当技术方案确定后,我们可以让 Cursor 生成对应的代码。但如果代码量较大,或者使用的 AI 模型(如免费版)能力有限,我们可以每次让cursor实现一个功能模块而不是一次实现所有代码。
# Goal
Please generate the code according to the designed plan.
# Background Knowledge
To help you generate the code better, I have provided you with:
(1) Project code
(2) Requirements Document: "XX.md"
(3) Technical Solution: "XX.md"
(4) Project Understanding Document: "XX.md"
# Core Tasks
## 1. Document Analysis and Understanding stage
Complete the following analysis before starting to write the code:
- Demand matching degree check:
Gain a thorough understanding of the requirements document and the solution design document, and confirm the complete consistency between "Solution Design.MD" and "Requirement.MD" in terms of functional points, input and output, and abnormal scenarios.
If any contradiction is found, please mark it immediately and submit a note.
- Understanding of code architecture:
Gain a thorough understanding of the project's documentation and the hierarchical structure of the existing code base, and determine the insertion positions for new features.
List the reusable utility classes, exception handling mechanisms and common interfaces (such as the 'utils.py' and 'ErrorCode' enumeration classes).
2. Code generation stage
If you have clearly defined the requirements and technical solutions, please complete the code writing work.
# Requirement
1. You must follow the following core principles:
The code you generate must refer to the code style of the current project.
2. If the project already has available methods, it is necessary to consider reuse, extension of the existing methods, or method overloading to ensure the minimum granularity of changes and reduce repetitive code.
# Output
Please generate the code and place it in the appropriate position in the code base.
在代码编写完成后,可通过AI Agent实现自动化执行:自动安装依赖、运行测试并检测错误。我们也可以手动执行代码,当出现后端异常或前端Console/Network报错时,把错误提交给cursor让他帮忙做修复。理想的高效Agent 是可以一次生成可用的代码,顶多和人交互两三个轮次就能完成可用的代码。
生成单测
当代码可以跑通之后,我们可以继续给代码添加单元测试,来保证代码的可测试性。
# Task
Please generate a test for the xx file.
# Requirement
The unit test code you generate must refer to the existing single-test method style of the current project.
# Example
Copy a written single test from your current project as an example to prompt the large model.
CursorRules
目前 GitHub 上有一些开源项目分享了实用的 Cursor Rules 资源,例如 awesome-cursorrules 项目,我们可以根据自己的编程语言选择合适的规则集。
除了使用现成的规则外,还可以让 Cursor 根据项目特点自动生成适配的规则:
Analyze the project, output a rule developed in python, and write it into the cursorrules file of the project
在cursor里,我们可以为项目创建很多个cursorrules,每个cursorrules 对应开发的不同阶段。
项目文档规范Rule
# Project Documentation Standards
**The target audience of the documentation is explicitly software developers**, with the aim of helping the development team quickly understand the system architecture, business logic, and technical implementation details, facilitating code maintenance, feature expansion, and knowledge transfer.
## Key Rules
- Project documentation must include four core sections: Project Overview, Core Domain Model, Project Structure, and External Dependencies.
- Interface documentation must be written and maintained in accordance with the @Interface Documentation Standard.
- Business process documentation must be written and maintained in accordance with the @Business Process Documentation Standard.
- Documentation should remain objective, based on existing code rather than an idealized state.
- Terminology used in the documentation must align with the terminology in the code.
- Documentation should use Markdown format, supporting diagrams, tables, and code blocks.
- Code examples must be extracted from actual code, not fabricated.
- Diagrams should use Mermaid or PlantUML syntax to ensure maintainability.
- Documentation should reference specific code file paths to help readers locate related implementations.
- First, determine whether the project uses the GBF framework, and then select the appropriate documentation structure and content based on the actual architecture.
- All documentation must be uniformly placed in the `docs` directory and use the specified Chinese names.
- **The documentation generation process must ensure complete coverage of all content, with no omissions allowed.**
## Documentation Optimization and Structure Guidelines
- **Main Index Documentation**: Create a main index document for each core section, containing links to sub-documents and brief descriptions.
- **In-Document Navigation**: Documents exceeding 500 lines must include a table of contents at the beginning.
- **Hierarchical Structure**: Organize using the "Pyramid Structure" (top level: core concepts; middle level: main functional modules; bottom level: specific implementation details).
- **Document Splitting**: Split interfaces by business domain if they exceed 20; split core entities by business domain if they exceed 10.
## Documentation Structure and Content Requirements
### 1. Project Overview - `docs/Project Overview.md`
Must include: project background, project objectives, functional overview, technology stack, and architecture type (explicitly stating whether the GBF framework is used).
### 2. Core Domain Model - `docs/Domain Model Description.md`
Must include:
- Domain model overview: definitions and boundaries of core business concepts.
- Core entity-relationship diagram: represented using E-R diagrams or class diagrams.
- Model interactions in key business scenarios.
- Data flow relationships.
**Mandatory Domain Model Scanning Rules**:
- **Comprehensive Scan**: Includes `*Entity.java`, `*DO.java`, `*PO.java`, `*Model.java`, classes annotated with `@Entity`, `@Table`, `@Document`, core models in the service layer, and DTO/VO classes.
- **Directory Structure Identification**: Java class files located in `model`, `domain`, `entity` directories and their subdirectories, as well as class files under domain-specific package paths (e.g., `*.domain.*`, `*.model.*`, `*.entity.*`).
- **Complete Extraction**: Entity attributes and business meanings, entity relationships, aggregate structures, lifecycle, and state transitions.
- **Identification Rules**: Attribute constraints, entity relationship constraints, state transition rules.
**Domain Model Analysis Strategy**:
- Scan all entity classes and value objects, supporting multiple ORM frameworks.
- Extract associations (via field types, generic parameters, and ORM annotations).
- Identify aggregate roots and boundaries (via package structure and class relationships).
- Analyze inheritance structures (including abstract classes, interfaces, and implementation classes).
- Extract business methods and state transition logic.
- Generate complete attribute tables and business rule descriptions.
**GBF Framework Project Supplement**: Extension point definitions and implementations, industry/scenario customization points, routing conditions, and dynamic selection mechanisms.
### 3. Interface Documentation - `docs/Interface Documentation.md`
Interface documentation should be created and maintained in accordance with the dedicated @Interface Documentation Standard to ensure complete recording and updating of API interfaces.
### 4. Business Processes - `docs/Business Process Description.md`
Business process documentation should be created and maintained in accordance with the dedicated @Business Process Documentation Standard to ensure complete recording and updating of business processes.
### 5. Project Structure - `docs/Project Structure Description.md`
Must include: project module division, code organization structure, key package descriptions, and layered architecture explanation.
**GBF Framework Project Supplement** - `docs/GBF Framework Application Description.md`:
GBF layered structure, extension point file locations, industry customization directories, scenario customization directories.
### 6. External Dependencies and Downstream Services - `docs/External Dependencies Description.md`
Must include:
- Downstream service overview: list and purposes of all dependent external services.
- Call relationship diagram: system interactions with external services.
## Documentation Generation Workflow
1. **Architecture Identification**: Determine project architecture type, identify key components, and layered structure.
2. **Code Analysis**: Identify core business packages and classes, analyze domain models, extract interface definitions, and understand call chains.
3. **Content Organization**: Organize information according to documentation structure, extract code examples, and create diagrams.
4. **Review and Refinement**: Verify consistency between documentation and code, supplement key information, and refine diagrams and examples.
- **Interface Coverage Verification**: Ensure all interfaces in the overview document are fully described in detailed documentation.
- **Documentation Completeness Check**: Ensure no necessary interfaces or service descriptions are omitted.
5. **Regular Updates**: Integrate with code review processes, update documentation for major changes, and conduct comprehensive reviews quarterly.
## Examples
### Domain Model Example
```markdown
## Core Entity-Relationship Diagram
```mermaid
classDiagram
class Item {
+Long id
+String name
+BigDecimal price
+String status
+validatePrice()
+changeStatus(String)
}
class TyingRule {
+Long id
+Long mainItemId
+List<Long> subItemIds
+Date startTime
+Date endTime
+enable()
+disable()
}
Item "1" -- "n" TyingRule: Defined as main product
TyingRule "1" -- "n" Item: Associated bundled products
```
## Entity Attribute Details
### Item Product Entity
| Attribute | Type | Description |
|----|---|---|
| id | Long | Unique product identifier |
| name | String | Product name, length limit: 2-50 characters |
| price | BigDecimal | Product price, precise to 2 decimal places, minimum: 0.01 |
| status | String | Product status, enum values: ON_SHELF, OFF_SHELF, DELETED |
#### Business Rules
- Product price must be greater than 0.
- Product status can only transition in a specific flow (ON_SHELF -> OFF_SHELF -> DELETED).
```
### Business Process Example
```markdown
## Bundling Rule Creation Process
### Core Flowchart
```mermaid
flowchart TD
A[Create Request] --> B{Validate Parameters}
B -->|Invalid| C[Return Error]
B -->|Valid| D[Query Main Product]
D --> E{Product Exists?}
E -->|No| F[Return Error]
E -->|Yes| G[Query Bundled Products]
G --> H{Products Exist?}
H -->|No| I[Return Error]
H -->|Yes| J[Save Rule]
J --> K[Return Success]
```
### Call Chain
**Entry Point**: `ItemTyingController.createTyingRule()`
**Call Flow**:
1. Request parameter validation - `validateTyingRequest(request)`
2. Query main product information - `itemService.getItemById()`
3. Validate main product status - `validateItemStatus(item)`
4. Query and validate bundled product list - `validateSubItems()`
5. Build and save bundling rule - `tyingRuleRepository.save()`
6. Publish rule creation event - `eventPublisher.publishEvent()`
### Key Decision Points
| Decision Point | Condition | Handling Path |
|-----|---|----|
| Parameter Validation | Main product ID is empty | Return parameter error |
| Main Product Validation | Main product does not exist | Return product not found error |
| Bundled Product Validation | Invalid products exist | Return product invalid error |
```
代码分析规则Rule
# Code Analysis Rules
## Objective
Conduct in-depth analysis of complete business processes based on code entry points to generate detailed business process documentation, facilitating team understanding and code maintenance.
## Key Rules
- **Must generate analysis documents and save them in the project's `docs` directory**
- **Must use `sequential-thinking` to assist analysis**
- **Must delve into the internal logic of methods, which may require code retrieval**
- **Recommended to use `sequential-thinking` to assist in code retrieval**
### 1. Focus on Core Business Logic
- Ignore secondary logic such as logging and basic parameter validation
- Ignore technical details in exception handling, focusing only on business exception handling logic
- Ignore utility method calls unrelated to business (e.g., string manipulation, collection operations)
- Focus on key logic such as business state transitions, process branches, and core computations
### 2. Delve into Method Call Chains
- Trace the internal implementation of each key method, not just the method call level
- Analyze the internal business logic of each important method in the call chain
- For external dependencies (e.g., HSF, RPC calls), explain their functionality and business significance
- Conduct in-depth analysis of the conditions and handling logic for each key business branch
### 3. Leverage Existing Documentation
- Prioritize using descriptions from existing documentation to avoid redundant analysis
- If a method is already documented in detail, directly reference that content
- "Stand on the shoulders of giants" by supplementing and refining based on existing documentation
- Annotate discrepancies between existing documentation and code implementation
### 4. Documentation Output Standards
- Save analysis results in the `/docs` directory using Markdown format
- Document naming format: `BusinessName-ProcessAnalysis.md` (e.g., `OrderCreation-ProcessAnalysis.md`)
- Documents must include a method call tree to clearly display call hierarchy relationships
- Use step-by-step business process descriptions to outline the complete handling process
## Documentation Structure Template
```markdown
# Business Name Process Analysis
## Functional Overview
[Briefly describe the purpose and role of this business function]
## Entry Method
`com.example.Class.method`
## Method Call Tree
Entry Method
├─ Level 1 Method 1
│ ├─ Level 2 Method 1.1
│ ├─ Level 2 Method 1.2
├─ Level 1 Method 2
├─ Level 2 Method 2.1
└─ Level 2 Method 2.2
└─ Level 3 Method
## Detailed Business Process
1. [Step 1: Business logic description]
2. [Step 2: Business logic description]
- [Sub-step 2.1: Detailed logic]
- [Sub-step 2.2: Detailed logic]
3. [Step 3: Business logic description]
## Key Business Rules
- [Rule 1: Describe the business rule and its conditions]
- [Rule 2: Describe the business rule and its conditions]
## Data Flow
- Input: [Describe method input and its business meaning]
- Processing: [Describe key data processing and transformations]
- Output: [Describe method output and its business meaning]
## Extension Points/Branch Logic
- [Branch 1: Trigger conditions and handling logic]
- [Branch 2: Trigger conditions and handling logic]
## External Dependencies
- Note dependencies on external systems
## Notes
- [List points requiring special attention in the implementation]
## System Interaction Diagram
- If the business process involves multiple system modules, use PlantUML to draw a sequence diagram
## Code Analysis Techniques
### Step 1: Identify Business Entry Points
- Determine the starting point for code analysis (typically public methods in Controller, Facade, or Service layers)
- Understand the calling context and business background of the method
### Step 2: Build Method Call Trees
- Starting from the entry method, trace all important method calls
- Use indentation to represent call hierarchy, clearly displaying call relationships
- Ignore non-core method calls (e.g., logging, parameter validation)
### Step 3: Analyze Business Processes
- Analyze business processing steps in the order of code execution
- Focus on business state transitions and branch logic
- Extract key business rules and data processing logic
### Step 4: Organize Business Rules
- Summarize implicit business rules in conditional judgments
- Analyze handling differences under various scenarios
- Extract core decision points in business logic
### Step 5: Describe Data Flow
- Analyze the source, processing, and destination of key data
- Explain data model transformations and business meanings
- Track state changes of core business entities
## Example Analysis
Refer to the [OrderQuery.md](/docs/OrderQuery.md) document for a complete analysis example:
This example demonstrates a full analysis of the order query business, including:
- Method call tree showing the complete call chain
- Detailed business process broken down step-by-step
- Clear listing of key business rules
- Explicit description of external dependencies like HSF interfaces
- Detailed explanations of special handling logic (e.g., promotional refund button exposure)
## Characteristics of Good Analysis
1. **Completeness**: Covers all core business logic and branches
2. **Hierarchical Structure**: Clearly displays the hierarchy of processing flows
3. **Business-Oriented**: Described from a business perspective, not technical implementation details
4. **Accuracy**: Precisely reflects the actual processing logic in the code
5. **Clarity**: Expressed in a way that even business personnel can understand
6. **Practicality**: Helps readers quickly grasp business processes and rules
技术方案Rule
# 技术方案设计文档规范
## 关键规则
- 技术方案文档必须遵循规定的章节结构,包括名词解释、领域模型、应用调用关系和详细方案设计四个主要部分
- 名词解释部分必须建立业务和技术的统一语言,确保术语简单易懂
- 领域模型需清晰表达业务实体及其关系,可使用UML图或ER图进行可视化
- 应用调用关系必须体现跨应用的接口调用关系和消息队列的生产消费关系
- 详细方案设计应按应用和业务流程进行分类,对每个接口的改动点、代码分层和文档变更进行详细说明
- 代码改动点需重点突出实现思路,而不仅是罗列代码变更
- 对外接口协议的所有变更(包括字段变更等)必须在接口文档中明确体现
- 首先明确项目是否使用DDD框架或微服务架构,并选择相应的技术方案设计模板
- 使用DDD架构的项目,需明确说明各层级服务规划及领域边界设计
- 传统分层架构项目,应明确说明标准MVC或MVP分层架构设计
## 架构识别与方案适配
### 如何判断Python项目架构类型
#### DDD领域驱动设计架构
- 代码中存在Domain、Application、Infrastructure等包结构
- 存在Entity、ValueObject、DomainService、Repository等类
- 包结构中有domain、application、infrastructure、interface等目录
- 有明确的聚合根(AggregateRoot)和领域事件(DomainEvent)机制
#### 微服务架构
- 使用FastAPI、Flask或Django作为Web框架
- 存在独立的服务模块和API网关
- 使用消息队列(Redis、RabbitMQ、Kafka)进行服务间通信
- 有服务注册发现机制
#### 传统分层架构
- 标准的MVC或MVP模式
- Controller/View、Service、Repository/DAO层次结构
- 使用Flask、Django等传统Web框架
### 方案适配策略
- 使用DDD架构的项目,技术方案需关注领域边界设计和聚合设计
- 微服务架构项目,技术方案关注服务拆分和接口设计
- 传统分层架构项目,技术方案关注分层职责和数据流转
- 在方案开头明确说明项目所使用的架构模式
- 根据架构特点选择适当的设计模式和描述方式
## Python技术方案设计文档模板
```markdown
# 技术方案设计文档:[方案名称]
## 文档信息
- 作者:[作者姓名]
- 版本:[版本号,如v1.0]
- 日期:[创建/更新日期]
- 状态:[草稿/已评审/已确认]
- 架构类型:[DDD架构/微服务架构/传统分层架构] - Python版本:[Python版本号]
- 框架:[Flask/Django/FastAPI等] - 版本:[框架版本号]
# 一、名词解释
[建立业务和技术的统一语言,尽量简单易懂]
| 术语 | 解释 |
|---|---|
| 术语1 | 含义说明 |
| 术语2 | 含义说明 |
# 二、领域模型
[描述业务领域中的核心实体及其关系,推荐使用UML图表示]
## 核心实体
[列出核心业务实体及其属性、行为]
## 实体关系
[描述实体间的关系,可使用ER图]
```mermaid
classDiagram
class User {
+int id
+str username
+str email
+datetime created_at
+create_user()
+update_profile()
}
class Order {
+int id
+int user_id
+decimal total_amount
+str status
+datetime created_at
+create_order()
+update_status()
}
User ||--o{ Order : places
```
# 三、应用调用关系
[体现跨应用的接口调用关系、消息队列的生产消费关系]
## 系统架构图
[系统整体架构图,展示系统组件和交互关系]
```mermaid
flowchart TD
A[用户服务] -->|HTTP API| B[订单服务]
B -->|消息发送| C[Redis/RabbitMQ]
D[支付服务] -->|消息消费| C
D -->|数据存储| E[(PostgreSQL)]
F[API网关] --> A
F --> B
F --> D
```
## 时序图
[关键流程的时序图,展示组件间的交互顺序]
```mermaid
sequenceDiagram
participant Client as 客户端
participant Gateway as API网关
participant UserService as 用户服务
participant OrderService as 订单服务
participant PaymentService as 支付服务
Client->>Gateway: 创建订单请求
Gateway->>UserService: 验证用户信息
UserService-->>Gateway: 用户验证结果
Gateway->>OrderService: 创建订单
OrderService->>PaymentService: 发起支付
PaymentService-->>OrderService: 支付结果
OrderService-->>Gateway: 订单创建结果
Gateway-->>Client: 返回订单信息
```
# 四、详细方案设计
## 架构选型
[说明本方案采用的架构模式]
### 分层架构说明
[描述本方案的分层架构,说明各层职责]
#### DDD领域驱动设计架构(DDD架构项目)
```
# Interface层(接口层)
- Controllers:处理HTTP请求,参数校验和响应封装
- DTOs:数据传输对象,用于接口间数据传递
- Serializers:数据序列化和反序列化
# Application层(应用层)
- Services:应用服务,协调领域对象完成业务用例
- Commands/Queries:命令和查询对象,实现CQRS模式
- Handlers:命令和查询处理器
# Domain层(领域层)
- Entities:实体对象,包含业务逻辑和业务规则
- ValueObjects:值对象,不可变的业务概念
- DomainServices:领域服务,处理跨聚合的业务逻辑
- Repositories:仓储接口,定义数据访问抽象
# Infrastructure层(基础设施层)
- Repositories:仓储实现,具体的数据访问实现
- ExternalServices:外部服务集成
- Configuration:配置管理
```
#### 微服务架构(微服务架构项目)
```
# API Gateway层
- 路由转发、负载均衡、认证授权
- 限流熔断、监控日志
# Service层(各个微服务)
- Controllers:处理HTTP请求
- Services:业务逻辑处理
- Models:数据模型
- Repositories:数据访问
# Message Queue层
- Producers:消息生产者
- Consumers:消息消费者
- Event Handlers:事件处理器
# Infrastructure层
- Database:数据存储
- Cache:缓存服务
- Monitoring:监控服务
```
#### 传统分层架构(传统分层架构项目)
```
# Presentation层(表现层)
- Controllers/Views:处理HTTP请求,参数校验
- Templates:模板文件(如使用Django/Flask模板)
- Forms:表单处理和验证
- Serializers:数据序列化
# Business层(业务层)
- Services:实现业务逻辑
- Managers:业务管理器,协调多个服务
- Utils:业务工具类
# Data Access层(数据访问层)
- Models:数据模型(ORM模型)
- Repositories:数据访问抽象
- DAOs:数据访问对象
# Infrastructure层(基础设施层)
- Database:数据库配置和连接
- Cache:缓存配置
- External APIs:外部API集成
```
### 数据模型设计
[描述数据模型的设计,包括不同层次的数据模型]
```python
# DDD架构数据模型
# DTO (Data Transfer Object) - 接口层数据传输对象
@dataclass
class UserCreateDTO:
username: str
email: str
password: str
# Entity - 领域实体
class User(Entity):
def __init__(self, username: str, email: str, password_hash: str):
self.username = username
self.email = email
self.password_hash = password_hash
self.created_at = datetime.now()
def change_password(self, new_password: str) -> None:
# 业务规则:密码强度验证
if len(new_password) < 8:
raise DomainException("密码长度不能少于8位")
self.password_hash = hash_password(new_password)
# Model - 数据库模型(Infrastructure层)
class UserModel(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(50), unique=True, nullable=False)
email = Column(String(100), unique=True, nullable=False)
password_hash = Column(String(255), nullable=False)
created_at = Column(DateTime, default=datetime.utcnow)
```
```python
# 传统分层架构数据模型
# Form - 表单验证(Flask-WTF/Django Forms)
class UserRegistrationForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired(), Length(min=3, max=20)])
email = StringField('邮箱', validators=[DataRequired(), Email()])
password = PasswordField('密码', validators=[DataRequired(), Length(min=8)])
# Serializer - 数据序列化(Django REST Framework/Marshmallow)
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'created_at']
# Model - ORM模型
class User(db.Model): # SQLAlchemy/Django ORM
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
password_hash = db.Column(db.String(255), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
```
## 应用1
### 业务流程1
#### xxx接口
**接口说明**:[详细说明接口的用途和功能]
**接口路径**:[HTTP方法] [路径] 或 [RPC服务接口定义]
**请求参数**:
```json
{
"param1": "value1",
"param2": "value2"
}
```
**返回结果**:
```json
{
"code": 200,
"message": "success",
"data": {
"field1": "value1",
"field2": "value2"
}
}
```
#### 接口改动点
[说明接口的改动类型:新增、能力调整、扩展等,并详述改动内容]
#### 代码分层设计
[描述代码的分层结构,确保符合工程规范]
##### DDD架构分层设计(DDD架构项目)
```python
# Interface层 - 接口控制器
# 位置:src/interface/controllers/user_controller.py
from flask import Flask, request, jsonify
from src.application.services.user_service import UserService
from src.interface.dtos.user_dto import UserCreateDTO
class UserController:
def __init__(self, user_service: UserService):
self.user_service = user_service
def create_user(self):
"""创建用户接口"""
# 职责:参数校验、请求处理、结果封装
data = request.get_json()
user_dto = UserCreateDTO(**data)
result = self.user_service.create_user(user_dto)
return jsonify({"code": 200, "data": result})
# Application层 - 应用服务
# 位置:src/application/services/user_service.py
class UserService:
def __init__(self, user_repository: UserRepository):
self.user_repository = user_repository
def create_user(self, user_dto: UserCreateDTO) -> dict:
"""创建用户业务逻辑"""
# 职责:协调领域对象,实现业务用例
# 检查用户名是否存在
if self.user_repository.find_by_username(user_dto.username):
raise BusinessException("用户名已存在")
# 创建用户实体
user = User.create(
username=user_dto.username,
email=user_dto.email,
password=user_dto.password
)
# 保存用户
saved_user = self.user_repository.save(user)
return {"id": saved_user.id, "username": saved_user.username}
# Domain层 - 领域实体
# 位置:src/domain/entities/user.py
class User(Entity):
def __init__(self, username: str, email: str, password_hash: str):
# 职责:封装业务规则和业务逻辑
self.username = username
self.email = email
self.password_hash = password_hash
self.created_at = datetime.now()
@classmethod
def create(cls, username: str, email: str, password: str) -> 'User':
"""创建用户工厂方法"""
# 业务规则:用户名长度验证
if len(username) < 3:
raise DomainException("用户名长度不能少于3位")
# 业务规则:邮箱格式验证
if not cls._is_valid_email(email):
raise DomainException("邮箱格式不正确")
password_hash = hash_password(password)
return cls(username, email, password_hash)
# Infrastructure层 - 仓储实现
# 位置:src/infrastructure/repositories/user_repository.py
class SqlAlchemyUserRepository(UserRepository):
def __init__(self, session: Session):
self.session = session
def save(self, user: User) -> User:
"""保存用户到数据库"""
# 职责:将领域对象转换为数据库模型并持久化
user_model = UserModel(
username=user.username,
email=user.email,
password_hash=user.password_hash,
created_at=user.created_at
)
self.session.add(user_model)
self.session.commit()
# 转换回领域对象
return User(
username=user_model.username,
email=user_model.email,
password_hash=user_model.password_hash
)
```
##### 传统分层架构设计(传统分层架构项目)
```python
# Controller层 - Flask示例
# 位置:app/controllers/user_controller.py
from flask import Blueprint, request, jsonify
from app.services.user_service import UserService
user_bp = Blueprint('user', __name__)
@user_bp.route('/users', methods=['POST'])
def create_user():
"""创建用户接口"""
# 职责:参数校验、请求处理、结果封装
data = request.get_json()
# 参数校验
if not data.get('username') or not data.get('email'):
return jsonify({"code": 400, "message": "参数不完整"}), 400
# 调用服务层
user_service = UserService()
result = user_service.create_user(data)
return jsonify({"code": 200, "data": result})
# Service层 - 业务逻辑
# 位置:app/services/user_service.py
from app.models.user import User
from app.repositories.user_repository import UserRepository
class UserService:
def __init__(self):
self.user_repository = UserRepository()
def create_user(self, user_data: dict) -> dict:
"""创建用户业务逻辑"""
# 职责:实现业务逻辑,协调数据访问层
# 业务规则:检查用户名是否存在
if self.user_repository.find_by_username(user_data['username']):
raise BusinessException("用户名已存在")
# 业务规则:密码加密
user_data['password_hash'] = hash_password(user_data['password'])
del user_data['password']
# 创建用户
user = User(**user_data)
saved_user = self.user_repository.save(user)
return {
"id": saved_user.id,
"username": saved_user.username,
"email": saved_user.email
}
# Repository层 - 数据访问
# 位置:app/repositories/user_repository.py
from app.models.user import User
from app.extensions import db
class UserRepository:
def save(self, user: User) -> User:
"""保存用户到数据库"""
# 职责:封装数据访问逻辑
db.session.add(user)
db.session.commit()
return user
def find_by_username(self, username: str) -> User:
"""根据用户名查找用户"""
return User.query.filter_by(username=username).first()
# Model层 - 数据模型
# 位置:app/models/user.py
from app.extensions import db
from datetime import datetime
class User(db.Model):
"""用户模型"""
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
password_hash = db.Column(db.String(255), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
"""转换为字典"""
return {
'id': self.id,
'username': self.username,
'email': self.email,
'created_at': self.created_at.isoformat()
}
```
##### 微服务架构设计(微服务架构项目)
```python
# API Gateway - 网关路由
# 位置:gateway/main.py
from fastapi import FastAPI, HTTPException
import httpx
app = FastAPI()
@app.post("/api/users")
async def create_user_gateway(user_data: dict):
"""用户创建网关接口"""
# 职责:路由转发、认证授权、限流
# 认证检查
if not validate_token(request.headers.get('Authorization')):
raise HTTPException(status_code=401, detail="未授权")
# 转发到用户服务
async with httpx.AsyncClient() as client:
response = await client.post(
"http://user-service:8001/users",
jsnotallow=user_data
)
return response.json()
# User Service - 用户微服务
# 位置:services/user_service/main.py
from fastapi import FastAPI, Depends
from services.user_service.models import User
from services.user_service.repositories import UserRepository
app = FastAPI()
@app.post("/users")
async def create_user(
user_data: UserCreateRequest,
user_repo: UserRepository = Depends(get_user_repository)
):
"""创建用户"""
# 职责:处理用户相关的业务逻辑
# 检查用户是否存在
existing_user = await user_repo.find_by_username(user_data.username)
if existing_user:
raise HTTPException(status_code=400, detail="用户名已存在")
# 创建用户
user = User(
username=user_data.username,
email=user_data.email,
password_hash=hash_password(user_data.password)
)
saved_user = await user_repo.save(user)
# 发送用户创建事件
await publish_event("user.created", {
"user_id": saved_user.id,
"username": saved_user.username
})
return {"id": saved_user.id, "username": saved_user.username}
# Message Queue - 事件处理
# 位置:services/notification_service/consumers.py
import asyncio
from services.notification_service.email_service import EmailService
async def handle_user_created_event(event_data: dict):
"""处理用户创建事件"""
# 职责:处理异步事件,发送欢迎邮件
email_service = EmailService()
await email_service.send_welcome_email(
user_id=event_data['user_id'],
username=event_data['username']
)
```
#### 设计模式应用(Python特有)
##### 装饰器模式应用
```python
# 权限控制装饰器
from functools import wraps
from flask import request, jsonify
def require_auth(permission: str):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
token = request.headers.get('Authorization')
if not validate_token_permission(token, permission):
return jsonify({"code": 401, "message": "权限不足"}), 401
return f(*args, **kwargs)
return decorated_function
return decorator
# 使用示例
@user_bp.route('/users/<int:user_id>', methods=['DELETE'])
@require_auth('user:delete')
def delete_user(user_id):
# 删除用户逻辑
pass
```
##### 依赖注入模式
```python
# 依赖注入容器
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
class Container(containers.DeclarativeContainer):
# 配置
config = providers.Configuration()
# 数据库
database = providers.Singleton(
Database,
connection_string=config.database.connection_string
)
# 仓储
user_repository = providers.Factory(
SqlAlchemyUserRepository,
sessinotallow=database.provided.session
)
# 服务
user_service = providers.Factory(
UserService,
user_repository=user_repository
)
# 控制器中使用依赖注入
class UserController:
@inject
def __init__(self, user_service: UserService = Provide[Container.user_service]):
self.user_service = user_service
```
#### 代码改动点
[详述需要改动的代码,重点说明实现思路]
1. **Controller/View层改动**:
```python
# 新增用户管理控制器
# 位置:src/interface/controllers/user_controller.py
# 改动内容:新增用户CRUD接口
# 实现思路:使用Flask Blueprint组织路由,通过依赖注入获取服务实例
```
2. **Service层改动**:
```python
# 新增用户服务
# 位置:src/application/services/user_service.py
# 改动内容:实现用户注册、登录、信息更新等业务逻辑
# 实现思路:采用领域驱动设计,通过仓储模式访问数据
```
3. **Repository层改动**:
```python
# 新增用户仓储实现
# 位置:src/infrastructure/repositories/user_repository.py
# 改动内容:实现用户数据的CRUD操作
# 实现思路:使用SQLAlchemy ORM,实现仓储接口
```
4. **DDD特定改动(DDD架构项目)**:
```python
# 新增用户聚合根
# 位置:src/domain/aggregates/user_aggregate.py
# 改动内容:定义用户聚合的业务规则和不变量
# 实现思路:通过工厂方法创建实体,封装业务规则
```
5. **微服务特定改动(微服务架构项目)**:
```python
# 新增用户微服务
# 位置:services/user_service/
# 改动内容:独立的用户服务,包含完整的用户管理功能
# 实现思路:使用FastAPI构建REST API,通过消息队列与其他服务通信
```
## 数据库变更
### 表结构设计
[描述需要新增或修改的数据库表结构]
#### 表名:users
| 字段名 | 数据类型 | 是否为空 | 主键 | 默认值 | 注释 |
|----|---|---|---|---|---|
| id | BIGINT | 否 | 是 | AUTO_INCREMENT | 主键ID |
| username | VARCHAR(50) | 否 | 否 | - | 用户名 |
| email | VARCHAR(100) | 否 | 否 | - | 邮箱地址 |
| password_hash | VARCHAR(255) | 否 | 否 | - | 密码哈希 |
| status | TINYINT | 否 | 否 | 1 | 用户状态(1:正常,0:禁用) |
| created_at | DATETIME | 否 | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_at | DATETIME | 否 | 否 | CURRENT_TIMESTAMP ON UPDATE | 更新时间 |
### SQLAlchemy模型定义
```python
# 位置:src/infrastructure/models/user_model.py
from sqlalchemy import Column, Integer, String, DateTime, Boolean
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime
Base = declarative_base()
class UserModel(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(String(50), unique=True, nullable=False, index=True)
email = Column(String(100), unique=True, nullable=False, index=True)
password_hash = Column(String(255), nullable=False)
status = Column(Boolean, default=True, nullable=False)
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
updated_at = Column(DateTime, default=datetime.utcnow, notallow=datetime.utcnow)
```
### 数据库迁移脚本(Alembic)
```python
# 位置:migrations/versions/001_create_users_table.py
"""create users table
Revision ID: 001
Revises:
Create Date: 2024-01-15 10:30:00.000000
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers
revision = '001'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
'users',
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
sa.Column('username', sa.String(length=50), nullable=False),
sa.Column('email', sa.String(length=100), nullable=False),
sa.Column('password_hash', sa.String(length=255), nullable=False),
sa.Column('status', sa.Boolean(), nullable=False, default=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('username'),
sa.UniqueConstraint('email')
)
# 创建索引
op.create_index('idx_users_username', 'users', ['username'])
op.create_index('idx_users_email', 'users', ['email'])
op.create_index('idx_users_created_at', 'users', ['created_at'])
def downgrade():
op.drop_table('users')
```
### 索引设计
| 索引名 | 字段 | 索引类型 | 说明 |
|----|---|---|---|
| PRIMARY | id | 主键 | 主键索引 |
| uk_username | username | 唯一 | 用户名唯一索引 |
| uk_email | email | 唯一 | 邮箱唯一索引 |
| idx_created_at | created_at | 普通 | 创建时间索引,用于排序查询 |
| idx_status | status | 普通 | 状态索引,用于筛选有效用户 |
## 接口文档变更
### API接口规范
[描述需要新增或修改的接口文档]
#### FastAPI自动文档生成
```python
# 位置:src/interface/schemas/user_schema.py
from pydantic import BaseModel, Field, EmailStr
from typing import Optional
from datetime import datetime
class UserCreateRequest(BaseModel):
"""用户创建请求"""
username: str = Field(..., min_length=3, max_length=50, descriptinotallow="用户名")
email: EmailStr = Field(..., descriptinotallow="邮箱地址")
password: str = Field(..., min_length=8, descriptinotallow="密码")
class UserResponse(BaseModel):
"""用户响应"""
id: int = Field(..., descriptinotallow="用户ID")
username: str = Field(..., descriptinotallow="用户名")
email: str = Field(..., descriptinotallow="邮箱地址")
status: bool = Field(..., descriptinotallow="用户状态")
created_at: datetime = Field(..., descriptinotallow="创建时间")
class Config:
from_attributes = True
# 位置:src/interface/controllers/user_controller.py
from fastapi import APIRouter, Depends, HTTPException, status
from src.interface.schemas.user_schema import UserCreateRequest, UserResponse
router = APIRouter(prefix="/api/v1/users", tags=["用户管理"])
@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(
user_data: UserCreateRequest,
user_service: UserService = Depends(get_user_service)
):
"""
创建用户
- **username**: 用户名,3-50个字符
- **email**: 邮箱地址,必须是有效的邮箱格式
- **password**: 密码,至少8个字符
"""
try:
user = await user_service.create_user(user_data)
return UserResponse.from_orm(user)
except UserExistsException:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="用户名或邮箱已存在"
)
```
### Flask-RESTX文档生成
```python
# 位置:src/interface/controllers/user_controller.py
from flask_restx import Namespace, Resource, fields
from flask import request
api = Namespace('users', descriptinotallow='用户管理相关操作')
# 定义请求模型
user_create_model = api.model('UserCreate', {
'username': fields.String(required=True, descriptinotallow='用户名', min_length=3, max_length=50),
'email': fields.String(required=True, descriptinotallow='邮箱地址'),
'password': fields.String(required=True, descriptinotallow='密码', min_length=8)
})
# 定义响应模型
user_response_model = api.model('UserResponse', {
'id': fields.Integer(descriptinotallow='用户ID'),
'username': fields.String(descriptinotallow='用户名'),
'email': fields.String(descriptinotallow='邮箱地址'),
'status': fields.Boolean(descriptinotallow='用户状态'),
'created_at': fields.DateTime(descriptinotallow='创建时间')
})
@api.route('/')
class UserListResource(Resource):
@api.expect(user_create_model)
@api.marshal_with(user_response_model, code=201)
@api.doc('create_user', descriptinotallow='创建新用户')
def post(self):
"""创建用户"""
data = request.get_json()
# 处理逻辑
pass
```
## 配置变更
### 应用配置
```python
# 位置:config/settings.py
import os
from typing import Optional
class Settings:
"""应用配置"""
# 应用基础配置
APP_NAME: str = "User Management System"
APP_VERSION: str = "1.0.0"
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true"
# 数据库配置
DATABASE_URL: str = os.getenv(
"DATABASE_URL",
"postgresql://user:password@localhost:5432/userdb"
)
# Redis配置
REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379/0")
# JWT配置
SECRET_KEY: str = os.getenv("SECRET_KEY", "your-secret-key")
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
# 邮件配置
SMTP_HOST: str = os.getenv("SMTP_HOST", "smtp.gmail.com")
SMTP_PORT: int = int(os.getenv("SMTP_PORT", "587"))
SMTP_USERNAME: str = os.getenv("SMTP_USERNAME", "")
SMTP_PASSWORD: str = os.getenv("SMTP_PASSWORD", "")
# 日志配置
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
LOG_FILE_PATH: str = os.getenv("LOG_FILE_PATH", "logs/app.log")
settings = Settings()
```
### Docker配置
```dockerfile
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# 安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```
```yaml
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/userdb
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
volumes:
- ./logs:/app/logs
db:
image: postgres:15
environment:
- POSTGRES_DB=userdb
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
```
## 测试策略
### 单元测试
```python
# 位置:tests/unit/test_user_service.py
import pytest
from unittest.mock import Mock, AsyncMock
from src.application.services.user_service import UserService
from src.domain.entities.user import User
from src.domain.exceptions import UserExistsException
class TestUserService:
@pytest.fixture
def user_repository_mock(self):
return Mock()
@pytest.fixture
def user_service(self, user_repository_mock):
return UserService(user_repository_mock)
def test_create_user_success(self, user_service, user_repository_mock):
# Arrange
user_data = {
"username": "testuser",
"email": "test@example.com",
"password": "password123"
}
user_repository_mock.find_by_username.return_value = None
user_repository_mock.save.return_value = User(**user_data)
# Act
result = user_service.create_user(user_data)
# Assert
assert result.username == "testuser"
user_repository_mock.save.assert_called_once()
def test_create_user_duplicate_username(self, user_service, user_repository_mock):
# Arrange
user_data = {
"username": "existinguser",
"email": "test@example.com",
"password": "password123"
}
user_repository_mock.find_by_username.return_value = User(**user_data)
# Act & Assert
with pytest.raises(UserExistsException):
user_service.create_user(user_data)
```
### 集成测试
```python
# 位置:tests/integration/test_user_api.py
import pytest
from fastapi.testclient import TestClient
from src.main import app
from src.infrastructure.database import get_db
from tests.fixtures.database import test_db
client = TestClient(app)
class TestUserAPI:
def test_create_user_integration(self, test_db):
# Arrange
user_data = {
"username": "integrationtest",
"email": "integration@example.com",
"password": "password123"
}
# Act
response = client.post("/api/v1/users/", jsnotallow=user_data)
# Assert
assert response.status_code == 201
data = response.json()
assert data["username"] == "integrationtest"
assert data["email"] == "integration@example.com"
assert "id" in data
```
## 非功能性需求
### 性能需求
- **响应时间**: 用户注册接口响应时间 < 500ms
- **并发量**: 支持1000个并发用户注册
- **吞吐量**: 每秒处理100个用户注册请求
### 可用性需求
- **系统可用率**:99.9%
- **故障恢复时间**: < 5分钟
- **数据备份**: 每日自动备份,保留30天
### 扩展性需求
- **水平扩展**: 支持通过增加服务实例来扩展处理能力
- **数据库分片**: 支持用户数据按用户ID分片存储
- **缓存策略**: 使用Redis缓存热点用户数据
## 兼容性与平滑迁移方案
### 版本兼容性
- **API版本控制**: 使用URL路径版本控制(/api/v1/, /api/v2/)
- **数据库迁移**: 使用Alembic进行数据库版本管理
- **向后兼容**: 新版本API保持对旧版本的兼容性
### 平滑迁移方案
```python
# 数据迁移脚本示例
# 位置:scripts/migrate_user_data.py
importasyncio
fromsrc.infrastructure.databaseimportget_db_session
fromsrc.infrastructure.models.user_modelimportUserModel
asyncdefmigrate_user_data():
"""迁移用户数据"""
asyncwithget_db_session() assession:
# 批量处理用户数据
batch_size = 1000
offset = 0
whileTrue:
users = awaitsession.execute(
select(UserModel).offset(offset).limit(batch_size)
)
user_list = users.scalars().all()
ifnotuser_list:
break
# 处理用户数据迁移逻辑
foruserinuser_list:
# 数据转换和更新
pass
awaitsession.commit()
offset += batch_size
print(f"已处理 {offset} 个用户")
if__name__ == "__main__":
asyncio.run(migrate_user_data())
```
## 风险与应对措施
| 风险 | 可能性 | 影响 | 应对措施 |
|---|----|---|---|
| 数据库连接池耗尽 | 中 | 高 | 配置连接池监控,实现连接池动态调整 |
| 密码哈希算法安全性 | 低 | 高 | 使用bcrypt或Argon2等安全哈希算法 |
| 邮箱验证服务不可用 | 中 | 中 | 实现邮件服务降级,支持多个邮件服务商 |
| 用户数据泄露 | 低 | 高 | 实现数据加密存储,定期安全审计 |
| 高并发下的性能问题 | 高 | 中 | 实现限流、缓存和异步处理 |
## Python特有的最佳实践
### 代码规范
```python
# 使用类型注解
fromtypingimportOptional, List, Dict, Any
defcreate_user(user_data:Dict[str, Any]) -> Optional[User]:
"""创建用户,返回用户对象或None"""
pass
# 使用dataclass简化数据类
from dataclasses import dataclass
@dataclass
class UserDTO:
username: str
email: str
password: str
def __post_init__(self):
"""数据验证"""
if len(self.username) < 3:
raise ValueError("用户名长度不能少于3位")
```
### 异步编程
```python
# 异步服务实现
import asyncio
from typing import List
class AsyncUserService:
async def create_users_batch(self, users_data: List[Dict]) -> List[User]:
"""批量创建用户"""
tasks = [self.create_user(user_data) for user_data in users_data]
return await asyncio.gather(*tasks)
async def create_user(self, user_data: Dict) -> User:
"""异步创建单个用户"""
# 异步数据库操作
user = await self.user_repository.save_async(user_data)
# 异步发送邮件
await self.email_service.send_welcome_email_async(user.email)
return user
```
### 上下文管理器
```python
# 数据库事务管理
from contextlib import asynccontextmanager
@asynccontextmanager
async def database_transaction():
"""数据库事务上下文管理器"""
session = get_db_session()
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
finally:
await session.close()
# 使用示例
async def create_user_with_profile(user_data: Dict, profile_data: Dict):
async with database_transaction() as session:
user = await create_user(user_data, session)
profile = await create_profile(profile_data, user.id, session)
return user, profile
```
## 示例
### DDD架构项目技术方案示例
#### 用户管理系统 - 创建用户功能
**架构类型**: DDD领域驱动设计架构 - Python 3.11 + FastAPI 0.104.1
##### 代码分层设计
```python
# Interface层 - 接口控制器
# 位置: src/interface/api/user_controller.py
from fastapi import APIRouter, Depends, HTTPException, status
from src.interface.schemas.user_schema import UserCreateRequest, UserResponse
from src.application.services.user_service import UserService
router = APIRouter(prefix="/api/v1/users", tags=["用户管理"])
@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(
user_request: UserCreateRequest,
user_service: UserService = Depends(get_user_service)
):
"""创建用户接口"""
# 职责:参数校验、请求处理、结果封装
try:
user = await user_service.create_user(user_request)
return UserResponse.from_domain(user)
except UserAlreadyExistsException as e:
raise HTTPException(status_code=400, detail=str(e))
# Application层 - 应用服务
# 位置: src/application/services/user_service.py
from src.domain.entities.user import User
from src.domain.repositories.user_repository import UserRepository
from src.domain.services.password_service import PasswordService
class UserService:
def __init__(self, user_repo: UserRepository, password_service: PasswordService):
self.user_repo = user_repo
self.password_service = password_service
async def create_user(self, request: UserCreateRequest) -> User:
"""创建用户应用服务"""
# 职责:协调领域对象,实现业务用例
# 检查用户是否已存在
existing_user = await self.user_repo.find_by_email(request.email)
if existing_user:
raise UserAlreadyExistsException("邮箱已被注册")
# 创建用户领域对象
user = User.create(
username=request.username,
email=request.email,
password=request.password,
password_service=self.password_service
)
# 保存用户
return await self.user_repo.save(user)
# Domain层 - 领域实体
# 位置: src/domain/entities/user.py
from dataclasses import dataclass
from datetime import datetime
from src.domain.value_objects.email import Email
from src.domain.value_objects.username import Username
from src.domain.services.password_service import PasswordService
@dataclass
class User:
"""用户聚合根"""
id: Optional[int] = None
username: Username = None
email: Email = None
password_hash: str = None
created_at: datetime = None
@classmethod
def create(cls, username: str, email: str, password: str,
password_service: PasswordService) -> 'User':
"""创建用户工厂方法"""
# 职责:封装用户创建的业务规则
# 验证用户名
username_vo = Username(username)
if not username_vo.is_valid():
raise InvalidUsernameException("用户名格式不正确")
# 验证邮箱
email_vo = Email(email)
if not email_vo.is_valid():
raise InvalidEmailException("邮箱格式不正确")
# 验证密码强度
if not password_service.is_strong_password(password):
raise WeakPasswordException("密码强度不够")
# 生成密码哈希
password_hash = password_service.hash_password(password)
return cls(
username=username_vo,
email=email_vo,
password_hash=password_hash,
created_at=datetime.now()
)
def change_password(self, new_password: str, password_service: PasswordService):
"""修改密码"""
if not password_service.is_strong_password(new_password):
raise WeakPasswordException("新密码强度不够")
self.password_hash = password_service.hash_password(new_password)
# Infrastructure层 - 仓储实现
# 位置: src/infrastructure/repositories/sqlalchemy_user_repository.py
from sqlalchemy.ext.asyncio import AsyncSession
from src.domain.repositories.user_repository import UserRepository
from src.infrastructure.models.user_model import UserModel
class SqlAlchemyUserRepository(UserRepository):
def __init__(self, session: AsyncSession):
self.session = session
async def save(self, user: User) -> User:
"""保存用户到数据库"""
# 职责:将领域对象转换为数据库模型并持久化
user_model = UserModel(
username=str(user.username),
email=str(user.email),
password_hash=user.password_hash,
created_at=user.created_at
)
self.session.add(user_model)
await self.session.commit()
await self.session.refresh(user_model)
# 转换回领域对象
return User(
id=user_model.id,
username=Username(user_model.username),
email=Email(user_model.email),
password_hash=user_model.password_hash,
created_at=user_model.created_at
)
```
根据上述DDD架构设计,创建用户功能的调用链为:
1. 客户端调用 `POST /api/v1/users/` 接口
2. UserController 接收请求并调用 UserService.create_user()
3. UserService 协调领域对象,调用 User.create() 工厂方法
4. User实体执行业务规则验证,创建用户对象
5. UserService 调用 UserRepository.save() 持久化用户
6. SqlAlchemyUserRepository 将领域对象转换为数据库模型并保存
7. 返回创建的用户对象,层层返回到客户端
### 传统分层架构项目技术方案示例
#### 博客系统 - 文章管理功能
**架构类型**: 传统分层架构 - Python 3.11 + Flask 2.3.3
##### 代码分层设计
```python
# Controller层 - Flask控制器
# 位置: app/controllers/article_controller.py
from flask import Blueprint, request, jsonify
from app.services.article_service import ArticleService
from app.schemas.article_schema import ArticleCreateSchema
article_bp = Blueprint('articles', __name__, url_prefix='/api/articles')
@article_bp.route('/', methods=['POST'])
def create_article():
"""创建文章接口"""
# 职责:参数校验、请求处理、结果封装
data = request.get_json()
# 参数验证
schema = ArticleCreateSchema()
try:
validated_data = schema.load(data)
except ValidationError as e:
return jsonify({"errors": e.messages}), 400
# 调用服务层
article_service = ArticleService()
try:
article = article_service.create_article(validated_data)
return jsonify(article.to_dict()), 201
except BusinessException as e:
return jsonify({"error": str(e)}), 400
# Service层 - 业务逻辑
# 位置: app/services/article_service.py
from app.models.article import Article
from app.repositories.article_repository import ArticleRepository
from app.utils.slug_generator import generate_slug
class ArticleService:
def __init__(self):
self.article_repo = ArticleRepository()
def create_article(self, article_data: dict) -> Article:
"""创建文章业务逻辑"""
# 职责:实现业务逻辑,协调数据访问层
# 业务规则:生成文章slug
slug = generate_slug(article_data['title'])
# 业务规则:检查slug是否重复
if self.article_repo.find_by_slug(slug):
slug = f"{slug}-{int(time.time())}"
# 业务规则:设置发布状态
article_data['slug'] = slug
article_data['status'] = 'draft' # 默认为草稿
article_data['created_at'] = datetime.now()
# 创建文章
article = Article(**article_data)
return self.article_repo.save(article)
def publish_article(self, article_id: int) -> Article:
"""发布文章"""
article = self.article_repo.find_by_id(article_id)
if not article:
raise ArticleNotFoundException("文章不存在")
# 业务规则:只有草稿状态的文章可以发布
if article.status != 'draft':
raise InvalidOperationException("只有草稿状态的文章可以发布")
article.status = 'published'
article.published_at = datetime.now()
return self.article_repo.save(article)
# Repository层 - 数据访问
# 位置: app/repositories/article_repository.py
from app.models.article import Article
from app.extensions import db
class ArticleRepository:
def save(self, article: Article) -> Article:
"""保存文章到数据库"""
# 职责:封装数据访问逻辑
db.session.add(article)
db.session.commit()
return article
def find_by_id(self, article_id: int) -> Article:
"""根据ID查找文章"""
return Article.query.get(article_id)
def find_by_slug(self, slug: str) -> Article:
"""根据slug查找文章"""
return Article.query.filter_by(slug=slug).first()
def find_published_articles(self, page: int = 1, per_page: int = 10):
"""查找已发布的文章"""
return Article.query.filter_by(status='published')\
.order_by(Article.published_at.desc())\
.paginate(page=page, per_page=per_page)
# Model层 - 数据模型
# 位置: app/models/article.py
from app.extensions import db
from datetime import datetime
class Article(db.Model):
"""文章模型"""
__tablename__ = 'articles'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
slug = db.Column(db.String(200), unique=True, nullable=False)
content = db.Column(db.Text, nullable=False)
status = db.Column(db.String(20), default='draft') # draft, published, archived
author_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
published_at = db.Column(db.DateTime)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, notallow=datetime.utcnow)
def to_dict(self):
"""转换为字典"""
return {
'id': self.id,
'title': self.title,
'slug': self.slug,
'content': self.content,
'status': self.status,
'author_id': self.author_id,
'created_at': self.created_at.isoformat() if self.created_at else None,
'published_at': self.published_at.isoformat() if self.published_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
```
根据上述传统分层架构设计,创建文章功能的调用链为:
1. 客户端调用 `POST /api/articles/` 接口
2. ArticleController 接收请求,验证参数
3. Controller 调用 ArticleService.create_article()
4. ArticleService 处理业务逻辑(生成slug、设置状态等)
5. Service 调用 ArticleRepository.save() 保存文章
6. Repository 使用 SQLAlchemy ORM 将文章保存到数据库
7. 返回创建的文章对象,层层返回到客户端
### 微服务架构项目技术方案示例
#### 电商系统 - 订单处理功能
**架构类型**: 微服务架构 - Python 3.11 + FastAPI 0.104.1 + Docker
##### 微服务架构设计
```python
# API Gateway - 网关服务
# 位置: gateway/main.py
from fastapi import FastAPI, HTTPException, Depends
from gateway.auth import verify_token
from gateway.routing import route_to_service
import httpx
app = FastAPI(title="电商系统API网关")
@app.post("/api/orders")
async def create_order_gateway(
order_data: dict,
user_id: str = Depends(verify_token)
):
"""订单创建网关接口"""
# 职责:路由转发、认证授权、限流
# 添加用户ID到请求数据
order_data['user_id'] = user_id
# 转发到订单服务
async with httpx.AsyncClient() as client:
response = await client.post(
"http://order-service:8001/orders",
jsnotallow=order_data,
timeout=30.0
)
if response.status_code != 201:
raise HTTPException(
status_code=response.status_code,
detail=response.json()
)
return response.json()
# Order Service - 订单微服务
# 位置: services/order_service/main.py
from fastapi import FastAPI, HTTPException, Depends
from services.order_service.models import Order, OrderItem
from services.order_service.services import OrderService
from services.order_service.schemas import OrderCreateRequest
from services.order_service.events import publish_event
app = FastAPI(title="订单服务")
@app.post("/orders", status_code=201)
async def create_order(
order_request: OrderCreateRequest,
order_service: OrderService = Depends(get_order_service)
):
"""创建订单"""
# 职责:处理订单相关的业务逻辑
try:
# 验证商品库存
await order_service.validate_inventory(order_request.items)
# 创建订单
order = await order_service.create_order(order_request)
# 发布订单创建事件
await publish_event("order.created", {
"order_id": order.id,
"user_id": order.user_id,
"total_amount": float(order.total_amount),
"items": [item.to_dict() for item in order.items]
})
return order.to_dict()
except InsufficientInventoryException as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail="订单创建失败")
# Inventory Service - 库存微服务
# 位置: services/inventory_service/main.py
from fastapi import FastAPI, HTTPException
from services.inventory_service.models import Inventory
from services.inventory_service.services import InventoryService
app = FastAPI(title="库存服务")
@app.post("/inventory/reserve")
async def reserve_inventory(
reserve_request: InventoryReserveRequest,
inventory_service: InventoryService = Depends(get_inventory_service)
):
"""预留库存"""
# 职责:处理库存预留逻辑
try:
reservation = await inventory_service.reserve_items(
reserve_request.items,
reserve_request.order_id
)
return {"reservation_id": reservation.id}
except InsufficientStockException as e:
raise HTTPException(status_code=400, detail=str(e))
# Payment Service - 支付微服务
# 位置: services/payment_service/consumers.py
import asyncio
from services.payment_service.services import PaymentService
from services.payment_service.events import consume_events
async def handle_order_created_event(event_data: dict):
"""处理订单创建事件"""
# 职责:处理异步事件,创建支付记录
payment_service = PaymentService()
# 创建支付记录
payment = await payment_service.create_payment(
order_id=event_data['order_id'],
amount=event_data['total_amount'],
user_id=event_data['user_id']
)
# 发布支付创建事件
await publish_event("payment.created", {
"payment_id": payment.id,
"order_id": payment.order_id,
"amount": float(payment.amount)
})
# Message Queue - 事件处理
# 位置: shared/events/event_bus.py
import asyncio
import json
from typing import Dict, Callable
import aio_pika
class EventBus:
def __init__(self, rabbitmq_url: str):
self.connection = None
self.channel = None
self.handlers: Dict[str, Callable] = {}
self.rabbitmq_url = rabbitmq_url
async def connect(self):
"""连接到RabbitMQ"""
self.connection = await aio_pika.connect_robust(self.rabbitmq_url)
self.channel = await self.connection.channel()
async def publish_event(self, event_type: str, event_data: dict):
"""发布事件"""
message = aio_pika.Message(
json.dumps({
"type": event_type,
"data": event_data,
"timestamp": time.time()
}).encode()
)
await self.channel.default_exchange.publish(
message,
routing_key=event_type
)
async def subscribe(self, event_type: str, handler: Callable):
"""订阅事件"""
queue = await self.channel.declare_queue(
f"{event_type}_queue",
durable=True
)
async def message_handler(message: aio_pika.IncomingMessage):
try:
event_data = json.loads(message.body.decode())
await handler(event_data['data'])
await message.ack()
except Exception as e:
print(f"Error handling event {event_type}: {e}")
await message.nack(requeue=True)
await queue.consume(message_handler)
# Docker Compose配置
# 位置: docker-compose.yml
version: '3.8'
services:
gateway:
build: ./gateway
ports:
- "8000:8000"
environment:
- ORDER_SERVICE_URL=http://order-service:8001
- INVENTORY_SERVICE_URL=http://inventory-service:8002
depends_on:
- order-service
- inventory-service
order-service:
build: ./services/order_service
ports:
- "8001:8001"
environment:
- DATABASE_URL=postgresql://postgres:password@postgres:5432/orders
- RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/
depends_on:
- postgres
- rabbitmq
inventory-service:
build: ./services/inventory_service
ports:
- "8002:8002"
environment:
- DATABASE_URL=postgresql://postgres:password@postgres:5432/inventory
- REDIS_URL=redis://redis:6379/0
depends_on:
- postgres
- redis
payment-service:
build: ./services/payment_service
environment:
- DATABASE_URL=postgresql://postgres:password@postgres:5432/payments
- RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/
depends_on:
- postgres
- rabbitmq
postgres:
image: postgres:15
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
rabbitmq:
image: rabbitmq:3-management
ports:
- "15672:15672"
volumes:
postgres_data:
```
根据上述微服务架构设计,创建订单功能的调用链为:
1. 客户端调用 API Gateway 的 `POST /api/orders` 接口
2. Gateway 验证用户身份,转发请求到 Order Service
3. Order Service 调用 Inventory Service 验证库存
4. Order Service 创建订单,发布 "order.created" 事件
5. Payment Service 消费事件,创建支付记录
6. 各服务将数据保存到各自的数据库
7. 返回订单创建结果,层层返回到客户端
## 方案设计工作流程
1. **架构识别阶段**
- 确定项目使用的Python框架(Django/Flask/FastAPI)
- 识别架构模式(DDD/微服务/传统分层)
- 确定数据库类型(PostgreSQL/MySQL/MongoDB)
- 识别消息队列和缓存方案
2. **需求分析阶段**
- 确定功能边界和核心业务流程
- 识别核心业务实体和领域模型
- 确定API接口设计和数据结构
- 识别异步处理需求
3. **方案设计阶段**
- 根据架构特点进行分层设计
- 确定接口实现和组件交互
- 设计数据库结构和ORM模型
- 对于微服务项目,设计服务拆分和通信机制
4. **方案评审阶段**
- 验证方案与Python最佳实践的一致性
- 验证功能覆盖度和完整性
- 评估性能问题和扩展性
- 确保方案文档结构清晰、内容完整
中间件规范Rule
# 中间件使用规范
---
description: `此规则适用于go项目的单元测试开发规范,Go单元测试提供全面指南,规范测试结构、mock技术和断言方法,确保测试代码质量与可维护性。`
globs:
alwaysApply: false
---
# 中间件客户端调用规范
## 关键规则
- **所有HTTP和HSF等中间件客户端必须放在framework/client目录下**
- **必须遵循统一的命名规范:服务功能+Service命名方式**
- **必须使用Context作为第一个参数,支持分布式追踪和日志记录**
- **中间件客户端必须从配置中心读取配置,不允许硬编码**
- **中间件调用必须记录完整的请求和响应日志**
- **必须实现统一的错误处理和返回机制**
- **应对关键调用实现缓存机制,减少直接调用次数**
- **请求和响应结构体必须实现JavaClassName方法(HSF特有)**
- **HSF服务必须在init方法中注册模型**
- **客户端调用需要进行合理的超时控制**
## HTTP客户端标准实现
### 客户端定义规范
```go
// 客户端标准定义
type XXXHttpClient struct {
// 可选的客户端配置
}
// 必须定义统一的初始化方法
func NewXXXHttpClient(ctx context.Context) *XXXHttpClient {
return &XXXHttpClient{}
}
```
### 请求参数定义
```go
// 请求参数必须使用结构体定义
type RequestParams struct {
// 请求字段
Field1 string `json:"field1"`
Field2 int `json:"field2"`
// ...
}
```
### 标准HTTP调用实现
```go
// 标准HTTP调用方法
func (client *XXXHttpClient) SendRequest(ctx context.Context, params RequestParams) (ResponseType, error) {
// 1. 从配置中心获取URL配置
var conf simplehttp.URLSetting
urlConf := mconfig.UrlConfig()
if err := urlConf.UnmarshalKey("ConfigKey", &conf); err != nil || conf.URL == "" {
return nil, common.Errorf(common.ErrorInternal, "url conf miss")
}
// 2. 构建URL和请求参数
url := conf.URL + "/api/endpoint"
httpParams := map[string]string{
"param1": params.Field1,
"param2": types.IWrapper(params.Field2).String(),
// 必须加入追踪ID
"trace_id": eagleeye.GetTraceId(ctx),
}
// 3. 构建请求选项
opt := simplehttp.BuildOptions(&simplehttp.Options{
Method: "GET", // 或 POST 等
Params: httpParams,
Timeout: conf.Timeout,
HostWithVip: conf.VipHost,
RecordWithParams: httpcommon.RecordWithParams,
})
// 4. 发送请求并记录日志
respData, err := simplehttp.RequestWithContext(ctx, url, opt)
common.LogInfof(ctx, "log_type", "request info, params=%v, err=%v", params, err)
// 5. 错误处理
if err != nil {
return nil, common.Errorf(common.ErrorInternal, "request failed.err:%s", err.Error())
}
// 6. 解析响应
var response ResponseType
err = json.Unmarshal(respData, &response)
if err != nil {
return nil, common.Errorf(common.ErrorInternal, "unmarshal failed.err:%s", err.Error())
}
// 7. 返回结果
return response, nil
}
```
### 带缓存的HTTP调用
```go
func GetDataWithCache(ctx context.Context, key string, params RequestParams) (ResponseType, error) {
var resp ResponseType
cacheKey := fmt.Sprintf("cache_key_prefix_%s", key)
// 使用缓存机制
err := mcache.GetLocalCacheFiveSecond(ctx).Once(ctx, cacheKey, &resp, 5*time.Second, func() (interface{}, error) {
// 调用实际API
data, e := SendRequest(ctx, params)
// 记录日志
common.LogDebugf(ctx, "module_name", "GetData, key:%s, data:%+v, err:%v", key, data, e)
// 错误处理
if e != nil {
return nil, errors.New(e.Error())
}
return data, nil
})
if err != nil {
return nil, err
}
return resp, nil
}
```
## HSF客户端标准实现
### 服务定义规范
```go
// 全局服务实例
var XXXService = new(XXXServiceImpl)
// 注册HSF模型
func init() {
hsfCommon.RegisterModel(&ModelType1{})
hsfCommon.RegisterModel(&ModelType2{})
// 其他模型注册...
}
// 服务结构体定义
type XXXServiceImpl struct {
// 方法定义,必须遵循标准方法签名
MethodName func(ctx context.Context, args []interface{}) (*ResponseType, error)
}
// 接口名配置
func (s *XXXServiceImpl) InterfaceName() string {
return mconfig.UrlConfig().GetString("ServiceName.interfaceName")
}
// 版本配置
func (s *XXXServiceImpl) Version() string {
return mconfig.UrlConfig().GetString("ServiceName.version")
}
// 组名配置
func (s *XXXServiceImpl) Group() string {
return mconfig.UrlConfig().GetString("ServiceName.group")
}
// 超时配置
func (s *XXXServiceImpl) TimeoutMs() int {
return mconfig.UrlConfig().GetInt("ServiceName.timeout")
}
```
### 请求模型定义
```go
// 请求模型必须实现JavaClassName方法
type RequestType struct {
Field1 string `json:"field1" hessian:"field1"`
Field2 int64 `json:"field2" hessian:"field2"`
// ...
}
func (RequestType) JavaClassName() string {
return"com.package.RequestType"
}
// 响应模型必须实现JavaClassName方法
type ResponseType struct {
Code int32 `json:"code"`
Data interface{} `json:"data"`
Success bool `json:"success"`
// ...
}
func (ResponseType) JavaClassName() string {
return"com.package.ResponseType"
}
```
### 标准HSF调用实现
```go
// 标准HSF调用方法
func CallHSFService(ctx context.Context, request *RequestType) (*DataType, *common.Error) {
// 1. 调用HSF服务
hsfResp, e := XXXService.MethodName(ctx, []interface{}{request})
// 2. 记录请求和响应日志
reqJson, _ := json.Marshal(request)
respJson, _ := json.Marshal(hsfResp)
common.LogInfof(ctx, "hsf_call", "hsf resp:%s, err:%v, req:%s",
string(respJson), e, string(reqJson))
// 3. 错误处理
if e != nil {
return nil, common.Errorf(common.ErrorInternal, "HSF call failed.err:%s", e.Error())
}
// 4. 结果处理
if hsfResp != nil {
result := ParseResponseData(hsfResp.Data)
return result, nil
}
return nil, nil
}
// 解析响应数据的标准方法
func ParseResponseData(data interface{}) *DataType {
if data == nil {
return nil
}
if items, ok := data.(SpecificResponseType); ok {
// 处理数据转换
result := &DataType{
// 数据转换逻辑
}
return result
}
return nil
}
```
### 带缓存的HSF调用
```go
func GetHSFDataWithCache(ctx context.Context, param1, param2 string) (*DataType, error) {
var resp *DataType
cacheKey := fmt.Sprintf("hsf_cache_key_%s_%s", param1, param2)
// 使用缓存机制
err := mcache.GetLocalCacheFiveSecond(ctx).Once(ctx, cacheKey, &resp, 5*time.Second, func() (interface{}, error) {
// 构建HSF请求
request := &RequestType{
Field1: param1,
Field2: param2,
}
// 调用HSF服务
data, e := CallHSFService(ctx, request)
// 记录日志
common.LogDebugf(ctx, "hsf_module", "GetHSFData, key:%s, data:%+v, err:%v", cacheKey, data, e)
// 错误处理
if e != nil {
return nil, errors.New(e.Error())
}
return data, nil
})
if err != nil {
return nil, err
}
return resp, nil
}
```
## 错误处理规范
- **所有中间件调用都必须返回标准化的错误**
- **错误必须包含错误码和错误信息**
- **网络错误必须归类为InternalError**
- **参数错误必须归类为InvalidError**
- **业务逻辑错误必须根据具体场景进行分类**
```go
// 错误处理示例
if err != nil {
// 网络错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
return nil, common.Errorf(common.ErrorTimeout, "request timeout: %s", err.Error())
}
// 一般错误
return nil, common.Errorf(common.ErrorInternal, "request failed: %s", err.Error())
}
// 业务错误
if resp.Code != 200 {
return nil, common.Errorf(common.ErrorBusiness, "business error: %s", resp.Message)
}
```
## 日志记录规范
- **所有中间件调用必须记录请求和响应日志**
- **日志必须包含追踪ID、请求参数和响应结果**
- **敏感信息(如密码、token)必须在日志中脱敏**
- **必须使用统一的日志模块和日志格式**
```go
// 标准日志示例
common.LogInfof(ctx, "module_name", "method_name, param1=%v, param2=%v, resp=%s, err=%v",
param1, param2, respJson, err)
```
## 示例
<example>
// HTTP客户端调用示例
package client
import (
"amap-aos-activity/basic/common"
"amap-aos-activity/framework/mconfig"
"context"
"encoding/json"
"fmt"
"gitlab.alibaba-inc.com/amap-go/eagleeye-go"
"gitlab.alibaba-inc.com/amap-go/http-client/simplehttp"
httpcommon "gitlab.alibaba-inc.com/amap-go/http-client/common"
"time"
)
// 请求参数定义
type SearchParams struct {
Query string `json:"query"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
}
// 响应结构定义
type SearchResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Data []SearchItem `json:"data"`
}
type SearchItem struct {
ID string `json:"id"`
Name string `json:"name"`
Distance float64 `json:"distance"`
}
// 发送搜索请求
func SendSearchRequest(ctx context.Context, params SearchParams) (*SearchResponse, *common.Error) {
// 从配置中获取URL
var conf simplehttp.URLSetting
urlConf := mconfig.UrlConfig()
if err := urlConf.UnmarshalKey("SearchService", &conf); err != nil || conf.URL == "" {
return nil, common.Errorf(common.ErrorInternal, "search service url conf miss")
}
// 构建请求参数
httpParams := map[string]string{
"query": params.Query,
"latitude": fmt.Sprintf("%f", params.Latitude),
"longitude": fmt.Sprintf("%f", params.Longitude),
"trace_id": eagleeye.GetTraceId(ctx),
}
// 构建请求选项
opt := simplehttp.BuildOptions(&simplehttp.Options{
Method: "GET",
Params: httpParams,
Timeout: conf.Timeout,
HostWithVip: conf.VipHost,
RecordWithParams: httpcommon.RecordWithParams,
})
// 发送请求
url := conf.URL + "/search/api"
respData, err := simplehttp.RequestWithContext(ctx, url, opt)
common.LogInfof(ctx, "search_service", "search request, params=%v, err=%v", params, err)
// 错误处理
if err != nil {
return nil, common.Errorf(common.ErrorInternal, "search request failed: %s", err.Error())
}
// 解析响应
var response SearchResponse
if err := json.Unmarshal(respData, &response); err != nil {
return nil, common.Errorf(common.ErrorInternal, "unmarshal search response failed: %s", err.Error())
}
// 业务错误处理
if response.Code != 200 {
return nil, common.Errorf(common.ErrorBusiness, "search business error: %s", response.Message)
}
return &response, nil
}
// 带缓存的搜索请求
func SearchWithCache(ctx context.Context, params SearchParams) (*SearchResponse, error) {
var resp *SearchResponse
cacheKey := fmt.Sprintf("search_%s_%f_%f", params.Query, params.Latitude, params.Longitude)
err := mcache.GetLocalCacheFiveSecond(ctx).Once(ctx, cacheKey, &resp, 30*time.Second, func() (interface{}, error) {
result, e := SendSearchRequest(ctx, params)
if e != nil {
return nil, e
}
return result, nil
})
if err != nil {
return nil, err
}
return resp, nil
}
</example>
<example>
// HSF客户端调用示例
package client
import (
"amap-aos-activity/basic/common"
"amap-aos-activity/framework/mconfig"
"context"
"encoding/json"
"errors"
"fmt"
hsfCommon "gitlab.alibaba-inc.com/amap-go/hsf-go/common"
"time"
)
// 全局服务实例
var ProductService = new(ProductServiceImpl)
// 注册HSF模型
func init() {
hsfCommon.RegisterModel(&ProductQueryRequest{})
hsfCommon.RegisterModel(&ProductQueryResponse{})
hsfCommon.RegisterModel(&ProductDetail{})
}
// 请求模型
type ProductQueryRequest struct {
ProductId string `json:"productId" hessian:"productId"`
Fields []string `json:"fields" hessian:"fields"`
}
func (ProductQueryRequest) JavaClassName() string {
return"com.example.product.request.ProductQueryRequest"
}
// 响应模型
type ProductQueryResponse struct {
Code int32 `json:"code"`
Data *ProductDetail `json:"data"`
Success bool `json:"success"`
Message string `json:"message"`
}
func (ProductQueryResponse) JavaClassName() string {
return"com.example.product.response.ProductQueryResponse"
}
// 产品详情
type ProductDetail struct {
Id string `json:"id" hessian:"id"`
Name string `json:"name" hessian:"name"`
Price int64 `json:"price" hessian:"price"`
Description string `json:"description" hessian:"description"`
}
func (ProductDetail) JavaClassName() string {
return"com.example.product.model.ProductDetail"
}
// 服务结构体
type ProductServiceImpl struct {
QueryProduct func(ctx context.Context, args []interface{}) (*ProductQueryResponse, error)
}
// 接口配置
func (s *ProductServiceImpl) InterfaceName() string {
return mconfig.UrlConfig().GetString("ProductService.interfaceName")
}
func (s *ProductServiceImpl) Version() string {
return mconfig.UrlConfig().GetString("ProductService.version")
}
func (s *ProductServiceImpl) Group() string {
return mconfig.UrlConfig().GetString("ProductService.group")
}
func (s *ProductServiceImpl) TimeoutMs() int {
return mconfig.UrlConfig().GetInt("ProductService.timeout")
}
// 查询产品信息
func GetProductDetail(ctx context.Context, productId string) (*ProductDetail, *common.Error) {
// 构建请求
request := &ProductQueryRequest{
ProductId: productId,
Fields: []string{"id", "name", "price", "description"},
}
// 调用HSF服务
resp, err := ProductService.QueryProduct(ctx, []interface{}{request})
// 记录日志
reqJson, _ := json.Marshal(request)
respJson, _ := json.Marshal(resp)
common.LogInfof(ctx, "product_service", "query product, req=%s, resp=%s, err=%v",
string(reqJson), string(respJson), err)
// 错误处理
if err != nil {
return nil, common.Errorf(common.ErrorInternal, "query product failed: %s", err.Error())
}
// 结果处理
if resp != nil {
if !resp.Success || resp.Code != 200 {
return nil, common.Errorf(common.ErrorBusiness, "business error: %s", resp.Message)
}
return resp.Data, nil
}
return nil, common.Errorf(common.ErrorInternal, "empty response")
}
// 带缓存的产品查询
func GetProductWithCache(ctx context.Context, productId string) (*ProductDetail, error) {
var product *ProductDetail
cacheKey := fmt.Sprintf("product_detail_%s", productId)
err := mcache.GetLocalCacheFiveSecond(ctx).Once(ctx, cacheKey, &product, 5*time.Minute, func() (interface{}, error) {
detail, e := GetProductDetail(ctx, productId)
if e != nil {
return nil, errors.New(e.Error())
}
return detail, nil
})
if err != nil {
return nil, err
}
return product, nil
}
</example>
<example type="invalid">
// 错误示例:硬编码URL和缺少日志记录
package client
import (
"context"
"encoding/json"
"net/http"
"io/ioutil"
)
// 错误1: 硬编码URL
// 错误2: 没有使用配置中心
// 错误3: 没有传递和使用context
func BadSearchRequest(query string) ([]byte, error) {
// 硬编码URL
url := "http://search.example.com/api?query=" + query
// 没有超时控制
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// 没有日志记录
return ioutil.ReadAll(resp.Body)
}
// 错误示例:HSF调用不规范
var badHsfService = struct {
Method func(args []interface{}) (interface{}, error)
}{}
// 错误1: 不遵循标准接口定义
// 错误2: 没有使用Context参数
// 错误3: 没有注册模型
// 错误4: 错误处理不规范
func BadHsfCall(id string) interface{} {
result, _ := badHsfService.Method([]interface{}{id})
// 忽略错误处理
return result
}
</example>
MCP
MCP作为cursor的加强工具,可以让工作中更加流畅,可以在MCP广场获取你想要的 MCP广场,比如我们可以在日常开发中飞书用的比较多,就可以使用飞书的mcp工具,实现文档处理、对话管理、日程安排等多种自动化场景。这个过程是增量的,当日常工作中有MCP的需求时,就可以搜索对应的MCP服务并应用到cursor中。
总结
根据团队成员的反馈,Cursor在提升编程效率方面基本达到了预期。现在,甚至项目经理(PM)也开始使用Cursor编写脚本,而不再像以前那样依赖研发人员。当然,Cursor并非万能,面对一些复杂的大型需求时,其表现有点差强人意,在这一层面不知道最近大火的Claude Code和Argument Code的表现如何?
本文转载自AI 博物院 作者:longyunfeigu
