Files
2026-07-13 12:34:57 +08:00

441 lines
14 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
约定优于配置示例应用
展示 MyBoot 框架的约定优于配置特性
"""
import sys
import threading
from pathlib import Path
from myboot.core.application import Application
from myboot.core.config import get_config
from myboot.core.decorators import (
get, post, put, delete,
cron, interval, once,
service, client, middleware,
rest_controller, component
)
from myboot.jobs.scheduled_job import ScheduledJob
from myboot.core.scheduler import get_scheduler
# 添加项目根目录到 Python 路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
# 创建应用实例
app = Application(
name="约定优于配置示例",
auto_configuration=True, # 启用自动配置
auto_discover_package="examples.convention_app"
)
# ==================== 服务层 ====================
@service()
class UserService:
"""用户服务 - 自动注册为 'user_service'"""
def __init__(self):
self.users = {}
print("✅ UserService 已初始化")
def get_user(self, user_id: int):
"""获取用户"""
return self.users.get(user_id, {"id": user_id, "name": f"用户{user_id}"})
def create_user(self, name: str, email: str):
"""创建用户"""
user_id = len(self.users) + 1
user = {"id": user_id, "name": name, "email": email}
self.users[user_id] = user
return user
def update_user(self, user_id: int, **kwargs):
"""更新用户"""
if user_id in self.users:
self.users[user_id].update(kwargs)
return self.users[user_id]
return None
def delete_user(self, user_id: int):
"""删除用户"""
return self.users.pop(user_id, None)
@service('email_service')
class EmailService:
"""邮件服务 - 注册为 'email_service'"""
def __init__(self):
print("✅ EmailService 已初始化")
def send_email(self, to: str, subject: str, body: str):
"""发送邮件"""
print(f"📧 发送邮件到 {to}: {subject}")
return {"status": "sent", "to": to, "subject": subject}
# ==================== 客户端层 ====================
@client()
class DatabaseClient:
"""数据库客户端 - 自动注册为 'database_client'"""
def __init__(self):
print("✅ DatabaseClient 已初始化")
def connect(self):
"""连接数据库"""
print("🔗 连接数据库")
return True
def query(self, sql: str):
"""执行查询"""
print(f"📊 执行查询: {sql}")
return []
@client('redis_client')
class RedisClient:
"""Redis 客户端 - 注册为 'redis_client'"""
def __init__(self):
print("✅ RedisClient 已初始化")
self.value = None
def get(self, key: str):
"""获取缓存"""
print(f"📦 获取缓存: {key}")
return self.value
def set(self, key: str, value: str):
"""设置缓存"""
print(f"💾 设置缓存: {key} = {value}")
self.value = value
# ==================== 中间件 ====================
@middleware(order=1)
async def logging_middleware(request, next_handler):
"""日志中间件 - 自动注册,处理所有请求"""
print(f"📝 请求日志: {request.method} {request.url}")
response = await next_handler(request)
print(f"📝 响应日志: {response.status_code}")
return response
@middleware(order=2)
async def timing_middleware(request, next_handler):
"""计时中间件 - 自动注册,处理所有请求"""
import time
start_time = time.time()
response = await next_handler(request)
end_time = time.time()
elapsed = end_time - start_time
print(f"⏱️ 请求耗时: {elapsed:.3f}s - {request.method} {request.url.path}")
return response
@middleware(order=3, path_filter='/api/*')
async def api_middleware(request, next_handler):
"""API 中间件 - 只处理 /api/* 路径的请求"""
print(f"🔌 API 请求: {request.method} {request.url.path}")
# 可以在这里添加 API 特定的逻辑,如认证、限流等
response = await next_handler(request)
return response
@middleware(order=4, methods=['POST', 'PUT', 'PATCH'])
async def modify_middleware(request, next_handler):
"""修改操作中间件 - 只处理 POST、PUT、PATCH 请求"""
print(f"✏️ 修改操作: {request.method} {request.url.path}")
response = await next_handler(request)
return response
@middleware(
order=5,
path_filter=['/users/*', '/api/products/*'],
condition=lambda req: req.headers.get('user-agent', '').startswith('Mozilla')
)
async def browser_only_middleware(request, next_handler):
"""浏览器专用中间件 - 只处理浏览器请求且匹配特定路径"""
print(f"🌐 浏览器请求: {request.headers.get('user-agent', 'Unknown')}")
response = await next_handler(request)
return response
# ==================== 定时任务组件 ====================
# 注意:定时任务必须在 @component 装饰的类中定义,支持依赖注入
@component()
class ScheduledJobs:
"""定时任务组件 - 使用 @component 装饰器,支持依赖注入"""
def __init__(self):
print("✅ ScheduledJobs 已初始化")
@cron('0 */1 * * * *', enabled=True) # 每分钟执行
def heartbeat(self):
"""心跳任务"""
print("💓 心跳检测 - 系统运行正常")
@interval(minutes=10, enabled=get_config('jobs.cleanup_task.enabled', True))
def cleanup_task(self):
"""清理任务 - 从配置文件读取 enabled 状态"""
print("🧹 执行清理任务")
@once('2025-12-31 23:59:59')
def new_year_task(self):
"""新年任务"""
print("🎉 新年任务执行")
# ==================== REST 控制器 ====================
# 注意:路由必须在 @rest_controller 装饰的类中定义
@rest_controller('/')
class HomeController:
"""首页控制器"""
@get('/')
def home(self):
"""首页 - GET /"""
return {
"message": "欢迎使用 MyBoot 约定优于配置示例",
"features": [
"自动发现和注册组件",
"约定优于配置",
"零配置启动",
"REST 控制器",
"依赖注入",
"定时任务"
]
}
@rest_controller('/api/users')
class UserController:
"""用户控制器 - 使用依赖注入"""
def __init__(self, user_service: UserService, email_service: EmailService):
self.user_service = user_service
self.email_service = email_service
@get('/')
def list_users(self):
"""获取用户列表 - GET /api/users"""
return {"users": list(self.user_service.users.values())}
@get('/{user_id}')
def get_user(self, user_id: int):
"""获取单个用户 - GET /api/users/{user_id}"""
return self.user_service.get_user(user_id)
@post('/')
def create_user(self, name: str, email: str):
"""创建用户 - POST /api/users"""
user = self.user_service.create_user(name, email)
self.email_service.send_email(email, "欢迎注册", f"欢迎 {name} 注册我们的服务!")
return {"message": "用户创建成功", "user": user}
@put('/{user_id}')
def update_user(self, user_id: int, name: str = None, email: str = None):
"""更新用户 - PUT /api/users/{user_id}"""
update_data = {}
if name:
update_data['name'] = name
if email:
update_data['email'] = email
user = self.user_service.update_user(user_id, **update_data)
if user:
return {"message": "用户更新成功", "user": user}
return {"error": "用户不存在"}
@delete('/{user_id}')
def delete_user(self, user_id: int):
"""删除用户 - DELETE /api/users/{user_id}"""
user = self.user_service.delete_user(user_id)
if user:
return {"message": "用户删除成功", "user": user}
return {"error": "用户不存在"}
@rest_controller('/api/products')
class ProductController:
"""产品控制器 - 使用依赖注入"""
def __init__(self, redis_client: RedisClient):
self.redis_client = redis_client
self.products = {
1: {"id": 1, "name": "产品1", "price": 100},
2: {"id": 2, "name": "产品2", "price": 200}
}
@get('/')
def list_products(self):
"""获取产品列表 - GET /api/products"""
if self.redis_client:
print(self.redis_client.get('app_status'))
return {"products": list(self.products.values())}
@get('/{product_id}')
def get_product(self, product_id: int):
"""获取单个产品 - GET /api/products/{product_id}"""
return self.products.get(product_id, {"error": "产品不存在"})
@post('/')
def create_product(self, name: str, price: float):
"""创建产品 - POST /api/products"""
product_id = max(self.products.keys()) + 1
product = {"id": product_id, "name": name, "price": price}
self.products[product_id] = product
return {"message": "产品创建成功", "product": product}
@put('/{product_id}')
def update_product(self, product_id: int, name: str = None, price: float = None):
"""更新产品 - PUT /api/products/{product_id}"""
if product_id not in self.products:
return {"error": "产品不存在"}
if name:
self.products[product_id]['name'] = name
if price:
self.products[product_id]['price'] = price
return {"message": "产品更新成功", "product": self.products[product_id]}
@delete('/{product_id}')
def delete_product(self, product_id: int):
"""删除产品 - DELETE /api/products/{product_id}"""
if product_id in self.products:
product = self.products.pop(product_id)
return {"message": "产品删除成功", "product": product}
return {"error": "产品不存在"}
def generate_report(report_type: str):
"""生成报告任务"""
import time
print(f"开始生成 {report_type} 报告")
time.sleep(10) # 模拟报告生成
return {"type": report_type, "status": "completed"}
@rest_controller('/api/reports')
class ReportController:
"""报告控制器"""
def __init__(self):
self.scheduler = get_scheduler()
@post('/generate')
def create_report(self, report_type: str):
"""创建报告生成任务"""
# 创建自定义 ScheduledJob
class ReportJob(ScheduledJob):
def __init__(self, report_type: str):
super().__init__(
name=f"生成{report_type}报告",
timeout=300 # 5分钟超时
)
self.report_type = report_type
def run(self, *args, **kwargs):
return generate_report(self.report_type)
# 创建任务实例
job = ReportJob(report_type)
# 添加到调度器并执行
job_id = self.scheduler.add_scheduled_job(job)
thread = threading.Thread(target=job.execute)
thread.daemon = True
thread.start()
return {"message": "报告生成任务已创建", "job_id": job_id}
@get('/status/{job_id}')
def get_status(self, job_id: str):
"""查询任务状态"""
job = self.scheduler.get_scheduled_job(job_id)
if job:
return job.get_info()
return {"error": "任务不存在"}
# ==================== 启动钩子 ====================
@app.add_startup_hook
def startup_hook():
"""启动钩子"""
print("🚀 应用启动钩子执行")
from myboot.core.application import get_client
# 初始化数据库连接
db_client = get_client('database_client')
if db_client:
db_client.connect()
# 初始化 Redis 连接
redis_client = get_client('redis_client')
if redis_client:
redis_client.set('app_status', 'running')
@app.add_shutdown_hook
def shutdown_hook():
"""关闭钩子"""
print("🛑 应用关闭钩子执行")
# ==================== 主程序 ====================
if __name__ == "__main__":
print("=" * 60)
print("🎯 MyBoot 约定优于配置示例")
print("=" * 60)
print()
print("✨ 特性展示:")
print(" • 自动发现和注册组件")
print(" • 约定优于配置")
print(" • 零配置启动")
print(" • 自动服务注入")
print(" • 自动路由注册")
print(" • 自动任务调度")
print()
print("🌐 访问地址:")
print(" • 应用: http://localhost:8000")
print(" • API 文档: http://localhost:8000/docs")
print(" • 健康检查: http://localhost:8000/health")
print()
print("📚 API 端点(通过 @rest_controller 定义):")
print(" • GET / - 首页")
print(" • GET /api/users - 用户列表")
print(" • GET /api/users/{id} - 获取用户")
print(" • POST /api/users - 创建用户")
print(" • PUT /api/users/{id} - 更新用户")
print(" • DELETE /api/users/{id} - 删除用户")
print(" • GET /api/products - 产品列表")
print(" • GET /api/products/{id} - 获取产品")
print(" • POST /api/products - 创建产品")
print(" • PUT /api/products/{id} - 更新产品")
print(" • DELETE /api/products/{id} - 删除产品")
print()
print("⏰ 定时任务(通过 @component 组件定义):")
print(" • 心跳检测 (每分钟)")
print(" • 清理任务 (每10分钟)")
print(" • 新年任务 (2025-12-31 23:59:59)")
print()
print("=" * 60)
# 启动应用
app.run(host="0.0.0.0", port=8000, reload=False)