Преглед изворни кода

添加Go语言学习项目文档和物联网基站学习专案

Migeking пре 1 месец
родитељ
комит
83b8af0d73
50 измењених фајлова са 9848 додато и 1 уклоњено
  1. 193 0
      README.md
  2. 498 0
      docs/iot-base-station.md
  3. 133 0
      docs/phase1-basics.md
  4. 222 0
      docs/phase2-core.md
  5. 269 0
      docs/phase3-practice.md
  6. 443 0
      docs/phase4-project.md
  7. 646 0
      docs/web-special-training.md
  8. 39 0
      examples/basics/hello-world.go
  9. 38 0
      iot-base-station/.air.toml
  10. 57 0
      iot-base-station/Dockerfile
  11. 478 0
      iot-base-station/README.md
  12. 104 0
      iot-base-station/cmd/migrate/main.go
  13. 236 0
      iot-base-station/cmd/server/main.go
  14. 88 0
      iot-base-station/config/config.yaml
  15. 68 0
      iot-base-station/config/mosquitto.conf
  16. 195 0
      iot-base-station/docker-compose-without-redis.yml
  17. 231 0
      iot-base-station/docker-compose.yml
  18. 762 0
      iot-base-station/docs/infrastructure-setup.md
  19. 549 0
      iot-base-station/docs/local-development.md
  20. 28 0
      iot-base-station/go.mod
  21. 187 0
      iot-base-station/internal/device/device.go
  22. 347 0
      iot-base-station/internal/device/manager.go
  23. 339 0
      iot-base-station/internal/protocol/mqtt/adapter.go
  24. 1 0
      iot-base-station/migrations/000001_create_devices_table.down.sql
  25. 20 0
      iot-base-station/migrations/000001_create_devices_table.up.sql
  26. 1 0
      iot-base-station/migrations/000002_create_device_events_table.down.sql
  27. 19 0
      iot-base-station/migrations/000002_create_device_events_table.up.sql
  28. 131 0
      iot-base-station/scripts/health-check.sh
  29. 202 0
      iot-base-station/scripts/setup-dev.sh
  30. 84 0
      iot-base-station/scripts/start-infrastructure.sh
  31. 209 0
      iot-base-station/simulations/devices/temperature_sensor.go
  32. 59 0
      iot-base-station/simulations/main.go
  33. 0 1
      test1.txt
  34. 53 0
      web-training/Dockerfile
  35. 246 0
      web-training/README.md
  36. 156 0
      web-training/cmd/server/main.go
  37. 134 0
      web-training/config/config.go
  38. 38 0
      web-training/config/config.yaml
  39. 64 0
      web-training/docker-compose.yml
  40. 728 0
      web-training/docs/api.md
  41. 21 0
      web-training/go.mod
  42. 211 0
      web-training/internal/handler/user.go
  43. 155 0
      web-training/internal/middleware/auth.go
  44. 107 0
      web-training/internal/model/user.go
  45. 106 0
      web-training/internal/utils/response.go
  46. 104 0
      web-training/pkg/auth/jwt.go
  47. 124 0
      web-training/scripts/init.sql
  48. 275 0
      web-training/web/static/css/style.css
  49. 315 0
      web-training/web/static/js/main.js
  50. 135 0
      web-training/web/templates/index.html

+ 193 - 0
README.md

@@ -0,0 +1,193 @@
+# Go语言学习项目规划
+
+## 项目概述
+这是一个全面的Go语言学习项目,从基础语法到实战项目开发,帮助您系统掌握Go编程技能。
+
+## 学习阶段规划
+
+### 第一阶段:基础语法 (1-2周)
+
+#### 学习内容
+- Go语言简介与环境搭建
+- 基本语法结构(包、导入、函数)
+- 数据类型(基本类型、复合类型)
+- 变量与常量
+- 控制结构(if/else、for、switch)
+- 函数定义与调用
+
+#### 练习项目
+- 基础计算器
+- 温度转换器
+- 简单的文本处理工具
+
+#### 推荐资源
+- 《Go语言圣经》
+- Go官方文档
+- Tour of Go (官方教程)
+
+#### 评估方式
+- 代码练习完成度
+- 语法正确性检查
+- 基础算法实现
+
+### 第二阶段:核心概念 (2-3周)
+
+#### 学习内容
+- 指针与内存管理
+- 结构体与方法
+- 接口与多态
+- 错误处理机制
+- 并发编程基础(goroutine、channel)
+- 包管理与模块化
+
+#### 练习项目
+- 学生信息管理系统
+- 并发文件下载器
+- 简单的聊天服务器
+
+#### 推荐资源
+- 《Go语言实战》
+- Go by Example
+- Effective Go
+
+#### 评估方式
+- 接口设计合理性
+- 并发程序正确性
+- 错误处理完整性
+
+### 第三阶段:实战模块 (3-4周)
+
+#### 学习内容
+- 文件I/O操作
+- 网络编程(TCP/UDP、HTTP)
+- 数据库操作(SQL、NoSQL)
+- JSON/XML数据处理
+- 测试与调试
+- 性能优化
+
+#### 练习项目
+- 文件备份工具
+- Web爬虫
+- 数据库CRUD应用
+
+#### 推荐资源
+- 《Go Web编程》
+- Go标准库文档
+- 开源项目源码学习
+
+#### 评估方式
+- 功能完整性测试
+- 代码质量评估
+- 性能基准测试
+
+### 第四阶段:项目实践 (4-5周)
+
+#### 学习内容
+- RESTful API设计
+- 中间件开发
+- 认证与授权
+- 日志与监控
+- 部署与运维
+- 微服务架构
+
+#### 最终项目
+- 完整的RESTful API服务(用户管理系统)
+- 包含用户注册、登录、数据CRUD等功能
+
+#### 推荐资源
+- 《Go语言高级编程》
+- Gin/Echo框架文档
+- 云原生Go开发
+
+#### 评估方式
+- 项目功能完整性
+- 代码架构合理性
+- 性能与安全性评估
+
+### 第五阶段:Web开发特训 (8-10周)
+
+#### 学习内容
+- Web框架深度掌握(Gin/Echo)
+- 前后端分离架构设计
+- 高级Web特性(WebSocket、文件上传)
+- 性能优化与安全防护
+- 电商平台实战项目
+
+#### 特训项目
+- 完整的电商平台(用户管理、商品管理、购物车、订单、支付)
+- 包含前后端分离架构
+- 支持实时通信功能
+
+#### 推荐资源
+- 《Go Web编程》
+- Web框架官方文档
+- 现代Web开发最佳实践
+
+#### 评估方式
+- Web框架熟练度
+- 架构设计能力
+- 性能优化效果
+- 安全防护措施
+
+## 项目结构
+
+```
+Godemo/
+├── README.md                 # 项目说明
+├── docs/                     # 学习文档
+│   ├── phase1-basics.md     # 第一阶段文档
+│   ├── phase2-core.md       # 第二阶段文档
+│   ├── phase3-practice.md   # 第三阶段文档
+│   └── phase4-project.md    # 第四阶段文档
+├── examples/                 # 示例代码
+│   ├── basics/              # 基础语法示例
+│   ├── core-concepts/       # 核心概念示例
+│   ├── practical/           # 实战模块示例
+│   └── projects/            # 项目示例
+├── exercises/               # 练习项目
+│   ├── calculator/          # 计算器项目
+│   ├── file-downloader/    # 文件下载器
+│   ├── web-crawler/        # 网络爬虫
+│   └── rest-api/           # RESTful API
+└── tools/                   # 开发工具
+    ├── scripts/             # 辅助脚本
+    └── templates/           # 代码模板
+```
+
+## 学习建议
+
+### 时间安排
+- 每日学习时间:2-3小时
+- 每周项目练习:8-10小时
+- 总学习周期:10-14周
+
+### 学习方法
+1. **理论学习**:阅读文档和书籍
+2. **代码实践**:动手编写示例代码
+3. **项目驱动**:通过实际项目巩固知识
+4. **代码审查**:定期检查代码质量
+5. **持续改进**:不断优化和重构代码
+
+### 评估标准
+- **基础阶段**:语法掌握程度、代码规范
+- **核心阶段**:概念理解深度、设计能力
+- **实战阶段**:问题解决能力、代码质量
+- **项目阶段**:系统设计能力、工程实践
+
+## 环境要求
+
+- Go 1.19+ 
+- Git
+- 代码编辑器(VS Code/GoLand)
+- 数据库(MySQL/PostgreSQL)
+- API测试工具(Postman/curl)
+
+## 开始学习
+
+1. 安装Go开发环境
+2. 克隆本项目
+3. 按照阶段顺序学习
+4. 完成每个阶段的练习项目
+5. 最终完成RESTful API项目
+
+祝您学习顺利!

+ 498 - 0
docs/iot-base-station.md

@@ -0,0 +1,498 @@
+# 物联网基站学习专案
+
+## 项目概述
+
+物联网基站学习专案是一个基于Go语言的综合性IoT基站管理系统,涵盖了从基础硬件通信到高级数据分析的全栈开发技能。通过这个项目,您将掌握物联网系统的核心技术和实际应用。
+
+## 学习目标
+
+- 掌握物联网通信协议(MQTT、CoAP、LoRaWAN)
+- 理解基站设备管理和数据处理
+- 学会实时数据采集与存储
+- 掌握数据可视化和分析技术
+- 能够构建完整的IoT解决方案
+
+## 技术架构
+
+### 硬件层
+- 传感器节点(温度、湿度、光照、空气质量等)
+- 通信模块(WiFi、LoRa、NB-IoT)
+- 边缘计算设备
+- 基站控制器
+
+### 通信层
+- MQTT消息代理
+- CoAP协议支持
+- LoRaWAN网络服务器
+- 数据加密与安全传输
+
+### 平台层
+- 设备管理服务
+- 数据采集服务
+- 规则引擎
+- 告警系统
+
+### 应用层
+- 实时监控仪表板
+- 历史数据分析
+- 预测性维护
+- 移动端应用
+
+## 学习阶段规划
+
+### 第一阶段:IoT基础与通信协议 (2-3周)
+
+#### 学习内容
+- 物联网基础概念
+- MQTT协议原理与应用
+- CoAP协议实现
+- LoRaWAN网络架构
+- 数据序列化格式(JSON、Protocol Buffers)
+
+#### 实践项目
+- MQTT客户端/服务器实现
+- CoAP资源发现服务
+- LoRaWAN节点模拟器
+- 多协议数据网关
+
+#### 推荐资源
+- 《物联网导论》
+- MQTT官方文档
+- LoRa联盟技术规范
+- 《物联网通信协议》
+
+#### 评估方式
+- 协议实现正确性
+- 数据传输可靠性
+- 设备连接稳定性
+
+### 第二阶段:基站设备管理 (2-3周)
+
+#### 学习内容
+- 设备注册与认证
+- 设备状态监控
+- 远程配置管理
+- 固件升级机制
+- 设备故障诊断
+
+#### 实践项目
+- 设备注册服务
+- 设备状态监控系统
+- OTA固件更新服务
+- 设备健康检查工具
+
+#### 推荐资源
+- 《嵌入式系统设计》
+- 设备管理最佳实践
+- OTA更新安全指南
+
+#### 评估方式
+- 设备管理功能完整性
+- 系统响应时间
+- 故障处理能力
+
+### 第三阶段:数据处理与存储 (3-4周)
+
+#### 学习内容
+- 时序数据库设计
+- 数据清洗与预处理
+- 实时流处理
+- 数据聚合与统计
+- 数据归档策略
+
+#### 实践项目
+- 时序数据库实现
+- 数据清洗管道
+- 实时数据处理服务
+- 数据聚合分析工具
+
+#### 推荐资源
+- 《时序数据库原理》
+- Apache Kafka文档
+- InfluxDB最佳实践
+
+#### 评估方式
+- 数据处理准确性
+- 系统吞吐量
+- 存储效率
+
+### 第四阶段:数据分析与可视化 (2-3周)
+
+#### 学习内容
+- 数据可视化技术
+- 实时仪表板设计
+- 历史数据分析
+- 趋势预测算法
+- 告警规则引擎
+
+#### 实践项目
+- 实时监控仪表板
+- 历史数据分析平台
+- 智能告警系统
+- 趋势预测工具
+
+#### 推荐资源
+- 《数据可视化原理》
+- Grafana文档
+- 机器学习基础
+
+#### 评估方式
+- 可视化效果
+- 数据分析准确性
+- 告警及时性
+
+### 第五阶段:高级应用开发 (3-4周)
+
+#### 学习内容
+- 边缘计算架构
+- 微服务设计
+- 容器化部署
+- 系统监控与日志
+- 安全防护机制
+
+#### 实践项目
+- 边缘计算节点
+- 微服务架构重构
+- 容器化部署方案
+- 系统监控平台
+
+#### 推荐资源
+- 《边缘计算技术》
+- 微服务架构设计
+- Docker与Kubernetes
+
+#### 评估方式
+- 系统架构合理性
+- 部署自动化程度
+- 系统稳定性
+
+## 项目结构
+
+```
+iot-base-station/
+├── README.md                 # 项目说明
+├── go.mod                    # 依赖管理
+├── config/                   # 配置文件
+│   ├── config.yaml          # 应用配置
+│   └── devices.yaml         # 设备配置
+├── cmd/                      # 应用入口
+│   ├── server/              # 主服务器
+│   ├── gateway/             # 数据网关
+│   └── monitor/             # 监控服务
+├── internal/                 # 内部包
+│   ├── config/              # 配置管理
+│   ├── device/              # 设备管理
+│   ├── protocol/            # 协议实现
+│   ├── storage/             # 数据存储
+│   ├── analytics/           # 数据分析
+│   └── notification/        # 通知服务
+├── pkg/                      # 公共包
+│   ├── mqtt/                # MQTT客户端
+│   ├── coap/                # CoAP客户端
+│   ├── lora/                # LoRaWAN客户端
+│   ├── database/            # 数据库连接
+│   └── security/            # 安全模块
+├── web/                      # Web界面
+│   ├── static/              # 静态资源
+│   └── templates/           # 模板文件
+├── scripts/                  # 脚本文件
+│   ├── setup.sh             # 环境设置
+│   └── deploy.sh            # 部署脚本
+├── docs/                     # 文档
+│   ├── api.md               # API文档
+│   ├── architecture.md      # 架构文档
+│   └── deployment.md        # 部署文档
+├── tests/                    # 测试文件
+├── simulations/              # 模拟器
+│   ├── devices/             # 设备模拟器
+│   └── network/             # 网络模拟器
+└── docker-compose.yml        # Docker配置
+```
+
+## 核心技术栈
+
+### 后端技术
+- **语言**: Go 1.19+
+- **Web框架**: Gin/Echo
+- **消息队列**: NATS/Redis
+- **时序数据库**: InfluxDB/TimescaleDB
+- **关系数据库**: PostgreSQL
+- **缓存**: Redis
+- **监控**: Prometheus + Grafana
+
+### 通信协议
+- **MQTT**: Eclipse Paho
+- **CoAP**: go-coap
+- **LoRaWAN**: ChirpStack
+- **HTTP**: RESTful API
+- **WebSocket**: 实时通信
+
+### 前端技术
+- **框架**: React/Vue.js
+- **图表库**: Chart.js/D3.js
+- **UI组件**: Ant Design/Element UI
+- **实时通信**: WebSocket/SSE
+
+### 部署技术
+- **容器化**: Docker
+- **编排**: Docker Compose/Kubernetes
+- **CI/CD**: GitLab CI/Jenkins
+- **监控**: Prometheus + Grafana
+
+## 实践项目详解
+
+### 项目1:多协议数据网关
+
+#### 功能描述
+实现一个支持MQTT、CoAP、LoRaWAN多种协议的数据网关,能够接收不同类型设备的数据并进行统一处理。
+
+#### 技术要点
+- 多协议适配器设计
+- 数据格式转换
+- 设备认证与授权
+- 数据路由与转发
+
+#### 实现步骤
+1. 设计协议适配器接口
+2. 实现MQTT协议适配器
+3. 实现CoAP协议适配器
+4. 实现LoRaWAN协议适配器
+5. 开发数据路由引擎
+6. 添加设备认证机制
+
+#### 代码示例
+```go
+// 协议适配器接口
+type ProtocolAdapter interface {
+    Name() string
+    Start() error
+    Stop() error
+    HandleMessage(msg Message) error
+}
+
+// MQTT适配器实现
+type MQTTAdapter struct {
+    client mqtt.Client
+    config MQTTConfig
+}
+
+func (m *MQTTAdapter) Start() error {
+    // 连接MQTT代理
+    // 订阅主题
+    // 设置消息处理器
+}
+
+func (m *MQTTAdapter) HandleMessage(msg Message) error {
+    // 解析MQTT消息
+    // 转换为统一格式
+    // 路由到处理器
+}
+```
+
+### 项目2:设备管理系统
+
+#### 功能描述
+实现完整的设备生命周期管理,包括设备注册、配置、监控、维护等功能。
+
+#### 技术要点
+- 设备注册与认证
+- 设备状态监控
+- 远程配置管理
+- OTA固件更新
+- 设备故障诊断
+
+#### 实现步骤
+1. 设计设备数据模型
+2. 实现设备注册服务
+3. 开发设备状态监控
+4. 实现远程配置功能
+5. 开发OTA更新服务
+6. 添加故障诊断功能
+
+#### 代码示例
+```go
+// 设备模型
+type Device struct {
+    ID          string            `json:"id"`
+    Name        string            `json:"name"`
+    Type        string            `json:"type"`
+    Protocol    string            `json:"protocol"`
+    Status      DeviceStatus      `json:"status"`
+    LastSeen    time.Time         `json:"last_seen"`
+    Metadata    map[string]string `json:"metadata"`
+    CreatedAt   time.Time         `json:"created_at"`
+    UpdatedAt   time.Time         `json:"updated_at"`
+}
+
+// 设备管理服务
+type DeviceManager struct {
+    repo   DeviceRepository
+    notifier Notifier
+}
+
+func (dm *DeviceManager) RegisterDevice(device *Device) error {
+    // 验证设备信息
+    // 生成设备ID
+    // 保存设备信息
+    // 发送通知
+}
+```
+
+### 项目3:实时数据处理平台
+
+#### 功能描述
+实现一个实时数据处理平台,能够接收、处理、存储和分析IoT设备产生的海量数据。
+
+#### 技术要点
+- 实时数据接收
+- 数据清洗与预处理
+- 时序数据存储
+- 实时数据分析
+- 数据可视化
+
+#### 实现步骤
+1. 设计数据接收管道
+2. 实现数据清洗逻辑
+3. 配置时序数据库
+4. 开发实时分析引擎
+5. 创建数据可视化界面
+
+#### 代码示例
+```go
+// 数据处理器
+type DataProcessor struct {
+    input    <-chan Message
+    output   chan<- ProcessedData
+    rules    []ProcessingRule
+    storage  DataStorage
+}
+
+func (dp *DataProcessor) Start() {
+    for msg := range dp.input {
+        // 应用处理规则
+        // 数据清洗
+        // 数据转换
+        // 存储处理结果
+    }
+}
+
+// 处理规则接口
+type ProcessingRule interface {
+    Name() string
+    Apply(data Message) (ProcessedData, error)
+}
+```
+
+### 项目4:智能告警系统
+
+#### 功能描述
+实现一个基于规则引擎的智能告警系统,能够根据设备数据变化自动触发告警。
+
+#### 技术要点
+- 规则引擎设计
+- 告警规则管理
+- 多级告警机制
+- 告警通知渠道
+- 告警抑制与恢复
+
+#### 实现步骤
+1. 设计规则引擎架构
+2. 实现规则解析器
+3. 开发告警评估器
+4. 实现多渠道通知
+5. 添加告警抑制机制
+
+#### 代码示例
+```go
+// 告警规则
+type AlertRule struct {
+    ID          string                 `json:"id"`
+    Name        string                 `json:"name"`
+    Description string                 `json:"description"`
+    Condition   string                 `json:"condition"`
+    Severity    AlertSeverity          `json:"severity"`
+    Actions     []AlertAction          `json:"actions"`
+    Enabled     bool                   `json:"enabled"`
+}
+
+// 规则引擎
+type RuleEngine struct {
+    rules    []AlertRule
+    evaluator ConditionEvaluator
+    notifier Notifier
+}
+
+func (re *RuleEngine) Evaluate(data ProcessedData) {
+    for _, rule := range re.rules {
+        if rule.Enabled && re.evaluator.Evaluate(rule.Condition, data) {
+            re.triggerAlert(rule, data)
+        }
+    }
+}
+```
+
+## 学习资源推荐
+
+### 书籍
+- 《物联网导论》- 吴功宜
+- 《物联网通信技术》- 王志良
+- 《时序数据库原理与实践》- 范湘涛
+- 《边缘计算:原理与实践》- 刘芳
+
+### 在线课程
+- Coursera: "IoT Programming and Big Data"
+- edX: "Introduction to Internet of Things"
+- 慕课网: "Go语言物联网开发实战"
+
+### 技术文档
+- MQTT官方文档
+- LoRaWAN规范
+- InfluxDB文档
+- Prometheus监控指南
+
+### 开源项目
+- Eclipse IoT项目
+- ChirpStack LoRaWAN网络服务器
+- ThingsBoard IoT平台
+- Home Assistant智能家居
+
+## 评估标准
+
+### 技术掌握程度 (40%)
+- 协议实现能力
+- 系统设计能力
+- 代码质量
+
+### 项目完成度 (30%)
+- 功能完整性
+- 系统稳定性
+- 性能指标
+
+### 创新与扩展 (20%)
+- 技术创新
+- 功能扩展
+- 优化改进
+
+### 文档与测试 (10%)
+- 文档完整性
+- 测试覆盖率
+- 部署指南
+
+## 学习建议
+
+1. **循序渐进**:从基础协议开始,逐步构建完整系统
+2. **实践为主**:每个知识点都要动手实现
+3. **系统思维**:关注整体架构,而非单一技术
+4. **持续学习**:关注IoT领域最新发展
+5. **社区参与**:积极参与开源项目和技术社区
+
+## 项目成果
+
+完成本专案后,您将拥有:
+1. 一个完整的IoT基站管理系统
+2. 多协议通信能力
+3. 实时数据处理经验
+4. 系统架构设计能力
+5. 物联网全栈开发技能
+
+这个专案将为您在物联网领域的发展奠定坚实基础!

+ 133 - 0
docs/phase1-basics.md

@@ -0,0 +1,133 @@
+# 第一阶段:Go语言基础语法
+
+## 学习目标
+- 掌握Go语言基本语法和编程范式
+- 理解Go的包管理和项目结构
+- 能够编写简单的Go程序
+
+## 详细学习内容
+
+### 1.1 Go语言简介
+- Go语言历史与设计哲学
+- Go语言特性(垃圾回收、并发支持等)
+- Go与其他语言的比较
+
+### 1.2 开发环境搭建
+- Go安装与配置
+- GOPATH与GOMODULE
+- 开发工具配置(VS Code/GoLand)
+
+### 1.3 基础语法
+```go
+// 包声明
+package main
+
+// 导入包
+import "fmt"
+
+// 主函数
+func main() {
+    fmt.Println("Hello, World!")
+}
+```
+
+### 1.4 数据类型
+- 基本类型:int, float, bool, string
+- 复合类型:数组、切片、映射
+- 类型转换与类型推断
+
+### 1.5 变量与常量
+```go
+// 变量声明
+var name string = "Go"
+var age = 25
+score := 95.5
+
+// 常量
+const PI = 3.14159
+const (
+    StatusOK = 200
+    StatusNotFound = 404
+)
+```
+
+### 1.6 控制结构
+- if/else条件判断
+- for循环(只有for一种循环)
+- switch多路选择
+- defer延迟执行
+
+### 1.7 函数
+- 函数定义与调用
+- 多返回值
+- 匿名函数与闭包
+- 函数作为参数
+
+## 练习项目
+
+### 项目1:基础计算器
+```go
+// 实现加减乘除运算
+func calculator(a, b float64, operator string) float64 {
+    // 实现逻辑
+}
+```
+
+### 项目2:温度转换器
+```go
+// 摄氏温度与华氏温度转换
+func celsiusToFahrenheit(c float64) float64
+func fahrenheitToCelsius(f float64) float64
+```
+
+### 项目3:文本统计工具
+```go
+// 统计文本中的字符数、单词数、行数
+func textStats(text string) (chars, words, lines int)
+```
+
+## 推荐资源
+
+### 在线教程
+- [Tour of Go](https://go.dev/tour/) - 官方交互式教程
+- [Go by Example](https://gobyexample.com/) - 代码示例集合
+
+### 书籍
+- 《Go语言圣经》- 经典入门教材
+- 《Go语言编程》- 实践导向
+
+### 视频课程
+- Go语言基础入门(慕课网)
+- Go语言核心编程(B站)
+
+## 评估方式
+
+### 代码练习评估
+1. **语法正确性**:代码能否编译通过
+2. **逻辑完整性**:功能是否完整实现
+3. **代码规范**:命名规范、注释完整性
+
+### 项目评估标准
+- 计算器项目:支持4种基本运算,错误处理
+- 温度转换:精确转换,支持双向转换
+- 文本统计:准确统计各类数据
+
+### 时间安排(1-2周)
+- 第1-3天:环境搭建与基础语法
+- 第4-7天:数据类型与控制结构
+- 第8-10天:函数与项目练习
+- 第11-14天:综合练习与复习
+
+## 常见问题
+
+### Q: Go的包管理如何使用?
+A: 使用go mod init初始化模块,go mod tidy管理依赖
+
+### Q: 为什么Go只有for循环?
+A: Go设计哲学强调简洁,for循环足够灵活
+
+### Q: defer的执行顺序?
+A: defer语句按照后进先出(LIFO)的顺序执行
+
+## 下一步
+完成本阶段学习后,进入第二阶段:核心概念学习

+ 222 - 0
docs/phase2-core.md

@@ -0,0 +1,222 @@
+# 第二阶段:Go语言核心概念
+
+## 学习目标
+- 深入理解Go语言的核心特性
+- 掌握面向对象编程在Go中的实现
+- 理解并发编程模型
+- 能够设计中等复杂度的Go程序
+
+## 详细学习内容
+
+### 2.1 指针与内存管理
+```go
+// 指针基础
+var x int = 10
+var p *int = &x
+*p = 20 // 修改x的值
+
+// new函数分配内存
+ptr := new(int)
+*ptr = 100
+```
+
+### 2.2 结构体与方法
+```go
+// 结构体定义
+type Person struct {
+    Name string
+    Age  int
+}
+
+// 方法定义
+func (p Person) SayHello() string {
+    return "Hello, " + p.Name
+}
+
+// 指针接收者
+func (p *Person) SetAge(age int) {
+    p.Age = age
+}
+```
+
+### 2.3 接口与多态
+```go
+// 接口定义
+type Shape interface {
+    Area() float64
+    Perimeter() float64
+}
+
+// 实现接口
+type Rectangle struct {
+    Width, Height float64
+}
+
+func (r Rectangle) Area() float64 {
+    return r.Width * r.Height
+}
+
+func (r Rectangle) Perimeter() float64 {
+    return 2 * (r.Width + r.Height)
+}
+```
+
+### 2.4 错误处理
+```go
+// 错误处理模式
+func divide(a, b float64) (float64, error) {
+    if b == 0 {
+        return 0, errors.New("division by zero")
+    }
+    return a / b, nil
+}
+
+// 自定义错误类型
+type MyError struct {
+    Code    int
+    Message string
+}
+
+func (e MyError) Error() string {
+    return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
+}
+```
+
+### 2.5 并发编程基础
+```go
+// goroutine
+func sayHello() {
+    fmt.Println("Hello from goroutine")
+}
+
+go sayHello() // 启动goroutine
+
+// channel通信
+ch := make(chan int)
+
+go func() {
+    ch <- 42 // 发送数据
+}()
+
+value := <-ch // 接收数据
+```
+
+### 2.6 包管理与模块化
+```go
+// go.mod文件示例
+module github.com/username/project
+
+go 1.19
+
+require (
+    github.com/gin-gonic/gin v1.9.0
+    github.com/go-sql-driver/mysql v1.7.0
+)
+```
+
+## 练习项目
+
+### 项目1:学生信息管理系统
+```go
+type Student struct {
+    ID    int
+    Name  string
+    Grade int
+    Score float64
+}
+
+// 实现增删改查功能
+type StudentManager struct {
+    students []Student
+}
+
+func (sm *StudentManager) AddStudent(s Student) error
+func (sm *StudentManager) FindStudentByID(id int) (Student, error)
+func (sm *StudentManager) UpdateStudent(s Student) error
+func (sm *StudentManager) DeleteStudent(id int) error
+```
+
+### 项目2:并发文件下载器
+```go
+// 使用goroutine并发下载多个文件
+func DownloadFiles(urls []string) error {
+    var wg sync.WaitGroup
+    errors := make(chan error, len(urls))
+    
+    for _, url := range urls {
+        wg.Add(1)
+        go func(url string) {
+            defer wg.Done()
+            if err := downloadFile(url); err != nil {
+                errors <- err
+            }
+        }(url)
+    }
+    
+    wg.Wait()
+    close(errors)
+    
+    // 处理错误
+    return nil
+}
+```
+
+### 项目3:简单的聊天服务器
+```go
+// 使用channel实现消息广播
+type ChatRoom struct {
+    messages chan string
+    clients  []chan string
+}
+
+func (cr *ChatRoom) Broadcast(message string)
+func (cr *ChatRoom) Join() chan string
+```
+
+## 推荐资源
+
+### 书籍
+- 《Go语言实战》- 实践性强的进阶教材
+- 《Go并发编程实战》- 深入理解并发
+- 《Go语言高级编程》- 系统学习高级特性
+
+### 在线资源
+- [Effective Go](https://go.dev/doc/effective_go) - Go官方最佳实践
+- [Go标准库文档](https://pkg.go.dev/std) - 标准库详细说明
+- [Go语言规范](https://go.dev/ref/spec) - 语言规范文档
+
+### 开源项目
+- [Gin Web框架](https://github.com/gin-gonic/gin) - 学习Web开发
+- [Cobra命令行库](https://github.com/spf13/cobra) - 学习CLI应用
+
+## 评估方式
+
+### 代码质量评估
+1. **接口设计**:接口是否合理,是否遵循单一职责原则
+2. **错误处理**:错误处理是否完整,是否提供有意义的错误信息
+3. **并发安全**:并发程序是否正确处理竞态条件
+
+### 项目评估标准
+- 学生管理系统:完整的CRUD操作,合理的错误处理
+- 文件下载器:并发下载,进度显示,错误恢复
+- 聊天服务器:多客户端支持,消息广播,连接管理
+
+### 时间安排(2-3周)
+- 第1-4天:指针、结构体、方法
+- 第5-8天:接口、错误处理
+- 第9-12天:并发编程基础
+- 第13-18天:项目练习与优化
+
+## 常见问题
+
+### Q: 什么时候使用值接收者,什么时候使用指针接收者?
+A: 需要修改接收者状态时用指针,否则用值接收者
+
+### Q: channel的缓冲和非缓冲有什么区别?
+A: 缓冲channel可以存储多个值,非缓冲channel需要同步发送接收
+
+### Q: 如何避免goroutine泄漏?
+A: 使用context控制goroutine生命周期,确保所有goroutine都能正常退出
+
+## 下一步
+完成本阶段学习后,进入第三阶段:实战模块开发

+ 269 - 0
docs/phase3-practice.md

@@ -0,0 +1,269 @@
+# 第三阶段:Go语言实战模块
+
+## 学习目标
+- 掌握Go语言在实际开发中的应用
+- 理解文件操作、网络编程、数据库连接
+- 能够开发完整的应用程序
+- 掌握测试和调试技巧
+
+## 详细学习内容
+
+### 3.1 文件I/O操作
+```go
+// 文件读写
+func readFile(filename string) (string, error) {
+    data, err := os.ReadFile(filename)
+    if err != nil {
+        return "", err
+    }
+    return string(data), nil
+}
+
+func writeFile(filename, content string) error {
+    return os.WriteFile(filename, []byte(content), 0644)
+}
+
+// 目录操作
+func listFiles(dir string) ([]string, error) {
+    entries, err := os.ReadDir(dir)
+    if err != nil {
+        return nil, err
+    }
+    
+    var files []string
+    for _, entry := range entries {
+        files = append(files, entry.Name())
+    }
+    return files, nil
+}
+```
+
+### 3.2 网络编程
+```go
+// HTTP客户端
+func httpGet(url string) (string, error) {
+    resp, err := http.Get(url)
+    if err != nil {
+        return "", err
+    }
+    defer resp.Body.Close()
+    
+    body, err := io.ReadAll(resp.Body)
+    if err != nil {
+        return "", err
+    }
+    return string(body), nil
+}
+
+// HTTP服务器
+func startHTTPServer() {
+    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+        fmt.Fprintf(w, "Hello, World!")
+    })
+    
+    http.ListenAndServe(":8080", nil)
+}
+
+// TCP服务器
+func startTCPServer() {
+    ln, err := net.Listen("tcp", ":8080")
+    if err != nil {
+        log.Fatal(err)
+    }
+    
+    for {
+        conn, err := ln.Accept()
+        if err != nil {
+            log.Println(err)
+            continue
+        }
+        go handleConnection(conn)
+    }
+}
+```
+
+### 3.3 数据库操作
+```go
+// MySQL连接
+func connectDB() (*sql.DB, error) {
+    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
+    if err != nil {
+        return nil, err
+    }
+    
+    if err := db.Ping(); err != nil {
+        return nil, err
+    }
+    
+    return db, nil
+}
+
+// CRUD操作
+type User struct {
+    ID   int
+    Name string
+    Age  int
+}
+
+func createUser(db *sql.DB, user User) error {
+    _, err := db.Exec("INSERT INTO users (name, age) VALUES (?, ?)", user.Name, user.Age)
+    return err
+}
+
+func getUserByID(db *sql.DB, id int) (User, error) {
+    var user User
+    err := db.QueryRow("SELECT id, name, age FROM users WHERE id = ?", id).Scan(&user.ID, &user.Name, &user.Age)
+    return user, err
+}
+```
+
+### 3.4 JSON/XML数据处理
+```go
+// JSON序列化与反序列化
+type Config struct {
+    Host string `json:"host"`
+    Port int    `json:"port"`
+}
+
+func saveConfig(config Config) error {
+    data, err := json.Marshal(config)
+    if err != nil {
+        return err
+    }
+    return os.WriteFile("config.json", data, 0644)
+}
+
+func loadConfig() (Config, error) {
+    data, err := os.ReadFile("config.json")
+    if err != nil {
+        return Config{}, err
+    }
+    
+    var config Config
+    err = json.Unmarshal(data, &config)
+    return config, err
+}
+```
+
+### 3.5 测试与调试
+```go
+// 单元测试
+func TestAdd(t *testing.T) {
+    result := add(2, 3)
+    if result != 5 {
+        t.Errorf("Expected 5, got %d", result)
+    }
+}
+
+// 基准测试
+func BenchmarkAdd(b *testing.B) {
+    for i := 0; i < b.N; i++ {
+        add(1, 2)
+    }
+}
+
+// 性能分析
+func profileCPU() {
+    f, err := os.Create("cpu.prof")
+    if err != nil {
+        log.Fatal(err)
+    }
+    defer f.Close()
+    
+    pprof.StartCPUProfile(f)
+    defer pprof.StopCPUProfile()
+    
+    // 执行需要分析的代码
+}
+```
+
+## 练习项目
+
+### 项目1:文件备份工具
+```go
+// 实现增量备份功能
+type BackupManager struct {
+    sourceDir string
+    backupDir string
+}
+
+func (bm *BackupManager) Backup() error
+func (bm *BackupManager) Restore(backupName string) error
+func (bm *BackupManager) ListBackups() ([]string, error)
+```
+
+### 项目2:Web爬虫
+```go
+// 并发爬取网页内容
+type Crawler struct {
+    visited map[string]bool
+    mutex   sync.Mutex
+}
+
+func (c *Crawler) Crawl(url string, depth int) ([]string, error)
+func (c *Crawler) extractLinks(html string) []string
+```
+
+### 项目3:数据库CRUD应用
+```go
+// 完整的用户管理系统
+type UserService struct {
+    db *sql.DB
+}
+
+func (us *UserService) CreateUser(user User) error
+func (us *UserService) GetUser(id int) (User, error)
+func (us *UserService) UpdateUser(user User) error
+func (us *UserService) DeleteUser(id int) error
+func (us *UserService) ListUsers() ([]User, error)
+```
+
+## 推荐资源
+
+### 书籍
+- 《Go Web编程》- Web开发实战
+- 《Go语言编程》- 综合应用
+- 《Go语言标准库》- 标准库详解
+
+### 在线资源
+- [Go官方博客](https://blog.golang.org/) - 官方技术文章
+- [Go语言中文网](https://studygolang.com/) - 中文社区资源
+- [Awesome Go](https://awesome-go.com/) - Go优秀项目集合
+
+### 工具
+- [Postman](https://www.postman.com/) - API测试
+- [MySQL Workbench](https://www.mysql.com/products/workbench/) - 数据库管理
+- [Wireshark](https://www.wireshark.org/) - 网络分析
+
+## 评估方式
+
+### 功能完整性测试
+1. **文件备份工具**:增量备份、恢复功能、备份列表
+2. **Web爬虫**:并发爬取、链接提取、去重处理
+3. **数据库应用**:完整CRUD操作、事务处理
+
+### 代码质量评估
+- 错误处理完整性
+- 代码可读性和可维护性
+- 性能优化程度
+- 测试覆盖率
+
+### 时间安排(3-4周)
+- 第1-5天:文件操作与网络编程
+- 第6-10天:数据库操作与数据处理
+- 第11-15天:测试与调试技巧
+- 第16-21天:项目练习与优化
+
+## 常见问题
+
+### Q: 如何处理大文件读写?
+A: 使用bufio.Scanner或分块读取,避免内存溢出
+
+### Q: 数据库连接池如何配置?
+A: 使用sql.DB的SetMaxOpenConns、SetMaxIdleConns等方法配置
+
+### Q: 如何调试并发程序?
+A: 使用race detector:go run -race main.go
+
+## 下一步
+完成本阶段学习后,进入第四阶段:完整项目实践

+ 443 - 0
docs/phase4-project.md

@@ -0,0 +1,443 @@
+# 第四阶段:完整项目实践 - RESTful API服务
+
+## 学习目标
+- 掌握完整的Web应用开发流程
+- 理解RESTful API设计原则
+- 能够构建生产级别的Go应用
+- 掌握部署和运维技能
+
+## 项目需求分析
+
+### 用户管理系统功能
+- 用户注册、登录、注销
+- 用户信息管理(增删改查)
+- 权限控制与认证
+- 数据验证与错误处理
+- 日志记录与监控
+
+## 技术栈选择
+
+### 核心框架
+- **Web框架**: Gin/Echo (推荐Gin)
+- **数据库**: MySQL/PostgreSQL
+- **ORM**: GORM
+- **认证**: JWT
+- **配置管理**: Viper
+- **日志**: Zap
+
+### 开发工具
+- **测试**: Go test + testify
+- **文档**: Swagger
+- **部署**: Docker
+- **监控**: Prometheus + Grafana
+
+## 项目架构设计
+
+### 目录结构
+```
+user-management/
+├── cmd/
+│   └── server/
+│       └── main.go          # 应用入口
+├── internal/
+│   ├── config/              # 配置管理
+│   ├── handler/             # HTTP处理器
+│   ├── middleware/          # 中间件
+│   ├── model/               # 数据模型
+│   ├── repository/          # 数据访问层
+│   ├── service/             # 业务逻辑层
+│   └── utils/               # 工具函数
+├── pkg/
+│   ├── auth/                # 认证模块
+│   ├── database/            # 数据库连接
+│   └── logger/              # 日志模块
+├── api/
+│   └── docs/                # API文档
+├── scripts/                 # 部署脚本
+├── docker-compose.yml       # Docker配置
+├── go.mod                   # 依赖管理
+└── README.md               # 项目说明
+```
+
+## 核心代码实现
+
+### 1. 配置管理 (config/config.go)
+```go
+package config
+
+type Config struct {
+    Server   ServerConfig   `mapstructure:"server"`
+    Database DatabaseConfig `mapstructure:"database"`
+    JWT      JWTConfig      `mapstructure:"jwt"`
+}
+
+type ServerConfig struct {
+    Port string `mapstructure:"port"`
+    Mode string `mapstructure:"mode"`
+}
+
+type DatabaseConfig struct {
+    Host     string `mapstructure:"host"`
+    Port     string `mapstructure:"port"`
+    User     string `mapstructure:"user"`
+    Password string `mapstructure:"password"`
+    DBName   string `mapstructure:"dbname"`
+}
+
+type JWTConfig struct {
+    Secret string `mapstructure:"secret"`
+    Expire int    `mapstructure:"expire"`
+}
+
+func Load() (*Config, error) {
+    // 实现配置加载逻辑
+}
+```
+
+### 2. 数据模型 (model/user.go)
+```go
+package model
+
+import "time"
+
+type User struct {
+    ID        uint      `gorm:"primaryKey" json:"id"`
+    Username  string    `gorm:"uniqueIndex;not null" json:"username"`
+    Email     string    `gorm:"uniqueIndex;not null" json:"email"`
+    Password  string    `gorm:"not null" json:"-"`
+    CreatedAt time.Time `json:"created_at"`
+    UpdatedAt time.Time `json:"updated_at"`
+}
+
+type CreateUserRequest struct {
+    Username string `json:"username" binding:"required,min=3,max=50"`
+    Email    string `json:"email" binding:"required,email"`
+    Password string `json:"password" binding:"required,min=6"`
+}
+
+type LoginRequest struct {
+    Username string `json:"username" binding:"required"`
+    Password string `json:"password" binding:"required"`
+}
+
+type UserResponse struct {
+    ID       uint   `json:"id"`
+    Username string `json:"username"`
+    Email    string `json:"email"`
+}
+```
+
+### 3. 业务逻辑层 (service/user_service.go)
+```go
+package service
+
+import (
+    "user-management/internal/model"
+    "user-management/internal/repository"
+    "golang.org/x/crypto/bcrypt"
+)
+
+type UserService struct {
+    userRepo repository.UserRepository
+}
+
+func NewUserService(repo repository.UserRepository) *UserService {
+    return &UserService{userRepo: repo}
+}
+
+func (s *UserService) CreateUser(req model.CreateUserRequest) (*model.UserResponse, error) {
+    // 密码加密
+    hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
+    if err != nil {
+        return nil, err
+    }
+    
+    user := &model.User{
+        Username: req.Username,
+        Email:    req.Email,
+        Password: string(hashedPassword),
+    }
+    
+    if err := s.userRepo.Create(user); err != nil {
+        return nil, err
+    }
+    
+    return &model.UserResponse{
+        ID:       user.ID,
+        Username: user.Username,
+        Email:    user.Email,
+    }, nil
+}
+
+func (s *UserService) Authenticate(req model.LoginRequest) (*model.User, error) {
+    user, err := s.userRepo.FindByUsername(req.Username)
+    if err != nil {
+        return nil, err
+    }
+    
+    if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
+        return nil, err
+    }
+    
+    return user, nil
+}
+```
+
+### 4. HTTP处理器 (handler/user_handler.go)
+```go
+package handler
+
+import (
+    "net/http"
+    "user-management/internal/model"
+    "user-management/internal/service"
+    "github.com/gin-gonic/gin"
+)
+
+type UserHandler struct {
+    userService *service.UserService
+    authService *service.AuthService
+}
+
+func NewUserHandler(userService *service.UserService, authService *service.AuthService) *UserHandler {
+    return &UserHandler{
+        userService: userService,
+        authService: authService,
+    }
+}
+
+// Register 用户注册
+// @Summary 用户注册
+// @Tags users
+// @Accept json
+// @Produce json
+// @Param user body model.CreateUserRequest true "用户信息"
+// @Success 201 {object} model.UserResponse
+// @Router /api/v1/register [post]
+func (h *UserHandler) Register(c *gin.Context) {
+    var req model.CreateUserRequest
+    if err := c.ShouldBindJSON(&req); err != nil {
+        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+        return
+    }
+    
+    user, err := h.userService.CreateUser(req)
+    if err != nil {
+        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+        return
+    }
+    
+    c.JSON(http.StatusCreated, user)
+}
+
+// Login 用户登录
+// @Summary 用户登录
+// @Tags users
+// @Accept json
+// @Produce json
+// @Param credentials body model.LoginRequest true "登录凭证"
+// @Success 200 {object} gin.H
+// @Router /api/v1/login [post]
+func (h *UserHandler) Login(c *gin.Context) {
+    var req model.LoginRequest
+    if err := c.ShouldBindJSON(&req); err != nil {
+        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+        return
+    }
+    
+    user, err := h.userService.Authenticate(req)
+    if err != nil {
+        c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
+        return
+    }
+    
+    token, err := h.authService.GenerateToken(user.ID)
+    if err != nil {
+        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+        return
+    }
+    
+    c.JSON(http.StatusOK, gin.H{
+        "token": token,
+        "user": model.UserResponse{
+            ID:       user.ID,
+            Username: user.Username,
+            Email:    user.Email,
+        },
+    })
+}
+```
+
+### 5. 中间件 (middleware/auth.go)
+```go
+package middleware
+
+import (
+    "net/http"
+    "strings"
+    "user-management/pkg/auth"
+    "github.com/gin-gonic/gin"
+)
+
+func AuthMiddleware(jwtService *auth.JWTService) gin.HandlerFunc {
+    return func(c *gin.Context) {
+        authHeader := c.GetHeader("Authorization")
+        if authHeader == "" {
+            c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少认证令牌"})
+            c.Abort()
+            return
+        }
+        
+        parts := strings.Split(authHeader, " ")
+        if len(parts) != 2 || parts[0] != "Bearer" {
+            c.JSON(http.StatusUnauthorized, gin.H{"error": "令牌格式错误"})
+            c.Abort()
+            return
+        }
+        
+        token := parts[1]
+        claims, err := jwtService.ValidateToken(token)
+        if err != nil {
+            c.JSON(http.StatusUnauthorized, gin.H{"error": "无效令牌"})
+            c.Abort()
+            return
+        }
+        
+        c.Set("userID", claims.UserID)
+        c.Next()
+    }
+}
+```
+
+## API接口设计
+
+### 用户管理接口
+| 方法 | 路径 | 描述 | 认证 |
+|------|------|------|------|
+| POST | /api/v1/register | 用户注册 | 否 |
+| POST | /api/v1/login | 用户登录 | 否 |
+| GET | /api/v1/users | 获取用户列表 | 是 |
+| GET | /api/v1/users/:id | 获取用户详情 | 是 |
+| PUT | /api/v1/users/:id | 更新用户信息 | 是 |
+| DELETE | /api/v1/users/:id | 删除用户 | 是 |
+
+## 部署配置
+
+### Docker配置 (docker-compose.yml)
+```yaml
+version: '3.8'
+services:
+  app:
+    build: .
+    ports:
+      - "8080:8080"
+    environment:
+      - DB_HOST=db
+      - DB_PORT=3306
+      - DB_USER=user
+      - DB_PASSWORD=password
+      - DB_NAME=user_management
+    depends_on:
+      - db
+    
+  db:
+    image: mysql:8.0
+    environment:
+      - MYSQL_ROOT_PASSWORD=root
+      - MYSQL_DATABASE=user_management
+      - MYSQL_USER=user
+      - MYSQL_PASSWORD=password
+    ports:
+      - "3306:3306"
+    volumes:
+      - db_data:/var/lib/mysql
+
+volumes:
+  db_data:
+```
+
+## 测试策略
+
+### 单元测试
+```go
+func TestUserService_CreateUser(t *testing.T) {
+    // 测试用户创建逻辑
+}
+
+func TestUserService_Authenticate(t *testing.T) {
+    // 测试用户认证逻辑
+}
+```
+
+### 集成测试
+```go
+func TestUserAPI(t *testing.T) {
+    // 测试完整的API流程
+}
+```
+
+### 性能测试
+```go
+func BenchmarkUserCreation(b *testing.B) {
+    // 性能基准测试
+}
+```
+
+## 评估标准
+
+### 功能完整性 (40%)
+- 所有API接口正常工作
+- 错误处理完整
+- 数据验证有效
+
+### 代码质量 (30%)
+- 代码结构清晰
+- 遵循Go最佳实践
+- 测试覆盖率达标
+
+### 性能与安全 (20%)
+- 响应时间合理
+- 安全措施到位
+- 资源使用优化
+
+### 文档与部署 (10%)
+- API文档完整
+- 部署流程顺畅
+- 监控配置完善
+
+## 时间安排 (4-5周)
+
+### 第1周:项目搭建与基础功能
+- 项目结构设计
+- 数据库设计
+- 基础CRUD功能
+
+### 第2周:认证与权限
+- JWT认证实现
+- 权限控制
+- 中间件开发
+
+### 第3周:高级功能
+- 数据验证
+- 错误处理
+- 日志记录
+
+### 第4周:测试与优化
+- 单元测试
+- 性能优化
+- 安全加固
+
+### 第5周:部署与文档
+- Docker部署
+- API文档
+- 监控配置
+
+## 项目成果
+
+完成本项目后,您将拥有:
+1. 一个完整的RESTful API服务
+2. 生产级别的Go应用开发经验
+3. 完整的开发-测试-部署流程
+4. 可复用的项目模板
+
+这个项目将为您后续的Go开发工作奠定坚实的基础!

+ 646 - 0
docs/web-special-training.md

@@ -0,0 +1,646 @@
+# Web开发特训章节
+
+## 学习目标
+- 掌握Go语言Web开发的核心技术栈
+- 理解现代Web应用架构设计
+- 能够独立开发生产级别的Web应用
+- 掌握前后端分离开发模式
+
+## 特训内容概览
+
+### 5.1 Web框架深度掌握 (2周)
+### 5.2 前后端分离架构 (2周)  
+### 5.3 高级Web特性 (2周)
+### 5.4 性能优化与安全 (1周)
+### 5.5 实战项目:电商平台 (3周)
+
+## 5.1 Web框架深度掌握
+
+### 5.1.1 Gin框架核心特性
+```go
+// 路由分组与中间件
+func setupRouter() *gin.Engine {
+    r := gin.Default()
+    
+    // 全局中间件
+    r.Use(gin.Logger())
+    r.Use(gin.Recovery())
+    
+    // API路由组
+    api := r.Group("/api/v1")
+    {
+        // 用户相关路由
+        users := api.Group("/users")
+        {
+            users.GET("", userHandler.ListUsers)
+            users.POST("", userHandler.CreateUser)
+            users.GET("/:id", userHandler.GetUser)
+            users.PUT("/:id", userHandler.UpdateUser)
+            users.DELETE("/:id", userHandler.DeleteUser)
+        }
+        
+        // 商品相关路由
+        products := api.Group("/products")
+        {
+            products.GET("", productHandler.ListProducts)
+            products.POST("", productHandler.CreateProduct)
+            products.GET("/:id", productHandler.GetProduct)
+        }
+    }
+    
+    return r
+}
+```
+
+### 5.1.2 自定义中间件开发
+```go
+// 日志中间件
+func LoggerMiddleware() gin.HandlerFunc {
+    return func(c *gin.Context) {
+        start := time.Now()
+        
+        c.Next()
+        
+        latency := time.Since(start)
+        status := c.Writer.Status()
+        method := c.Request.Method
+        path := c.Request.URL.Path
+        
+        log.Printf("[%s] %s %d %s", method, path, status, latency)
+    }
+}
+
+// 限流中间件
+func RateLimitMiddleware(limit int) gin.HandlerFunc {
+    limiter := rate.NewLimiter(rate.Limit(limit), limit)
+    
+    return func(c *gin.Context) {
+        if !limiter.Allow() {
+            c.JSON(429, gin.H{"error": "请求过于频繁"})
+            c.Abort()
+            return
+        }
+        c.Next()
+    }
+}
+
+// CORS中间件
+func CORSMiddleware() gin.HandlerFunc {
+    return func(c *gin.Context) {
+        c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
+        c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
+        c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
+        
+        if c.Request.Method == "OPTIONS" {
+            c.AbortWithStatus(204)
+            return
+        }
+        
+        c.Next()
+    }
+}
+```
+
+### 5.1.3 请求处理与数据绑定
+```go
+// 复杂数据绑定
+type CreateProductRequest struct {
+    Name        string  `json:"name" binding:"required,min=2,max=100"`
+    Description string  `json:"description" binding:"max=500"`
+    Price       float64 `json:"price" binding:"required,min=0"`
+    Stock       int     `json:"stock" binding:"min=0"`
+    CategoryID  uint    `json:"category_id" binding:"required"`
+    Images      []string `json:"images"`
+}
+
+// 文件上传处理
+func UploadHandler(c *gin.Context) {
+    file, err := c.FormFile("file")
+    if err != nil {
+        c.JSON(400, gin.H{"error": "文件上传失败"})
+        return
+    }
+    
+    // 验证文件类型
+    allowedTypes := map[string]bool{
+        "image/jpeg": true,
+        "image/png": true,
+        "image/gif": true,
+    }
+    
+    if !allowedTypes[file.Header.Get("Content-Type")] {
+        c.JSON(400, gin.H{"error": "不支持的文件类型"})
+        return
+    }
+    
+    // 保存文件
+    filename := fmt.Sprintf("uploads/%s", file.Filename)
+    if err := c.SaveUploadedFile(file, filename); err != nil {
+        c.JSON(500, gin.H{"error": "文件保存失败"})
+        return
+    }
+    
+    c.JSON(200, gin.H{"message": "上传成功", "filename": filename})
+}
+```
+
+## 5.2 前后端分离架构
+
+### 5.2.1 RESTful API设计规范
+```go
+// 统一响应格式
+type APIResponse struct {
+    Code    int         `json:"code"`
+    Message string      `json:"message"`
+    Data    interface{} `json:"data,omitempty"`
+    Meta    *MetaInfo   `json:"meta,omitempty"`
+}
+
+type MetaInfo struct {
+    Page      int `json:"page"`
+    PageSize  int `json:"page_size"`
+    Total     int `json:"total"`
+    TotalPage int `json:"total_page"`
+}
+
+// 成功响应
+func SuccessResponse(data interface{}) APIResponse {
+    return APIResponse{
+        Code:    200,
+        Message: "success",
+        Data:    data,
+    }
+}
+
+// 分页响应
+func PaginatedResponse(data interface{}, page, pageSize, total int) APIResponse {
+    totalPage := (total + pageSize - 1) / pageSize
+    
+    return APIResponse{
+        Code:    200,
+        Message: "success",
+        Data:    data,
+        Meta: &MetaInfo{
+            Page:      page,
+            PageSize:  pageSize,
+            Total:     total,
+            TotalPage: totalPage,
+        },
+    }
+}
+```
+
+### 5.2.2 JWT认证与权限控制
+```go
+// JWT服务
+type JWTService struct {
+    secretKey []byte
+}
+
+func NewJWTService(secret string) *JWTService {
+    return &JWTService{
+        secretKey: []byte(secret),
+    }
+}
+
+func (j *JWTService) GenerateToken(userID uint, roles []string) (string, error) {
+    claims := jwt.MapClaims{
+        "user_id": userID,
+        "roles":   roles,
+        "exp":     time.Now().Add(24 * time.Hour).Unix(),
+    }
+    
+    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+    return token.SignedString(j.secretKey)
+}
+
+func (j *JWTService) ValidateToken(tokenString string) (jwt.MapClaims, error) {
+    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
+        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+            return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
+        }
+        return j.secretKey, nil
+    })
+    
+    if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
+        return claims, nil
+    }
+    
+    return nil, err
+}
+
+// 基于角色的权限控制
+func RoleBasedAuth(requiredRoles ...string) gin.HandlerFunc {
+    return func(c *gin.Context) {
+        claims, exists := c.Get("claims")
+        if !exists {
+            c.JSON(401, gin.H{"error": "未授权"})
+            c.Abort()
+            return
+        }
+        
+        jwtClaims := claims.(jwt.MapClaims)
+        userRoles, ok := jwtClaims["roles"].([]interface{})
+        if !ok {
+            c.JSON(403, gin.H{"error": "权限不足"})
+            c.Abort()
+            return
+        }
+        
+        // 检查用户角色是否包含所需角色
+        hasPermission := false
+        for _, requiredRole := range requiredRoles {
+            for _, userRole := range userRoles {
+                if userRole == requiredRole {
+                    hasPermission = true
+                    break
+                }
+            }
+        }
+        
+        if !hasPermission {
+            c.JSON(403, gin.H{"error": "权限不足"})
+            c.Abort()
+            return
+        }
+        
+        c.Next()
+    }
+}
+```
+
+### 5.2.3 WebSocket实时通信
+```go
+// WebSocket连接管理
+type ConnectionManager struct {
+    connections map[*websocket.Conn]bool
+    broadcast   chan []byte
+    register    chan *websocket.Conn
+    unregister  chan *websocket.Conn
+    mutex       sync.RWMutex
+}
+
+func NewConnectionManager() *ConnectionManager {
+    return &ConnectionManager{
+        connections: make(map[*websocket.Conn]bool),
+        broadcast:   make(chan []byte),
+        register:    make(chan *websocket.Conn),
+        unregister:  make(chan *websocket.Conn),
+    }
+}
+
+func (cm *ConnectionManager) Run() {
+    for {
+        select {
+        case conn := <-cm.register:
+            cm.mutex.Lock()
+            cm.connections[conn] = true
+            cm.mutex.Unlock()
+            
+        case conn := <-cm.unregister:
+            cm.mutex.Lock()
+            if _, ok := cm.connections[conn]; ok {
+                delete(cm.connections, conn)
+                conn.Close()
+            }
+            cm.mutex.Unlock()
+            
+        case message := <-cm.broadcast:
+            cm.mutex.RLock()
+            for conn := range cm.connections {
+                if err := conn.WriteMessage(websocket.TextMessage, message); err != nil {
+                    cm.unregister <- conn
+                }
+            }
+            cm.mutex.RUnlock()
+        }
+    }
+}
+
+// WebSocket处理器
+func WebSocketHandler(cm *ConnectionManager) gin.HandlerFunc {
+    var upgrader = websocket.Upgrader{
+        CheckOrigin: func(r *http.Request) bool {
+            return true
+        },
+    }
+    
+    return func(c *gin.Context) {
+        conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
+        if err != nil {
+            log.Printf("WebSocket升级失败: %v", err)
+            return
+        }
+        
+        cm.register <- conn
+        
+        defer func() {
+            cm.unregister <- conn
+        }()
+        
+        for {
+            messageType, message, err := conn.ReadMessage()
+            if err != nil {
+                break
+            }
+            
+            // 处理接收到的消息
+            if messageType == websocket.TextMessage {
+                cm.broadcast <- message
+            }
+        }
+    }
+}
+```
+
+## 5.3 高级Web特性
+
+### 5.3.1 模板引擎与静态文件服务
+```go
+// HTML模板渲染
+func setupTemplateEngine() *gin.Engine {
+    r := gin.Default()
+    
+    // 加载模板
+    r.LoadHTMLGlob("templates/*")
+    
+    // 静态文件服务
+    r.Static("/static", "./static")
+    r.StaticFile("/favicon.ico", "./static/favicon.ico")
+    
+    return r
+}
+
+// 模板处理器
+func HomeHandler(c *gin.Context) {
+    c.HTML(200, "index.html", gin.H{
+        "title": "首页",
+        "user": gin.H{
+            "name": "张三",
+            "email": "[email protected]",
+        },
+    })
+}
+```
+
+### 5.3.2 文件上传与云存储集成
+```go
+// 多文件上传
+type UploadService struct {
+    cloudStorage CloudStorage
+}
+
+func (us *UploadService) UploadMultipleFiles(files []*multipart.FileHeader) ([]string, error) {
+    var uploadedFiles []string
+    
+    for _, file := range files {
+        filename, err := us.uploadSingleFile(file)
+        if err != nil {
+            return nil, err
+        }
+        uploadedFiles = append(uploadedFiles, filename)
+    }
+    
+    return uploadedFiles, nil
+}
+
+func (us *UploadService) uploadSingleFile(file *multipart.FileHeader) (string, error) {
+    // 打开文件
+    src, err := file.Open()
+    if err != nil {
+        return "", err
+    }
+    defer src.Close()
+    
+    // 生成唯一文件名
+    ext := filepath.Ext(file.Filename)
+    filename := fmt.Sprintf("%s%s", uuid.New().String(), ext)
+    
+    // 上传到云存储
+    if err := us.cloudStorage.Upload(filename, src); err != nil {
+        return "", err
+    }
+    
+    return filename, nil
+}
+```
+
+### 5.3.3 缓存与Session管理
+```go
+// Redis缓存服务
+type CacheService struct {
+    client *redis.Client
+}
+
+func NewCacheService(addr, password string) *CacheService {
+    client := redis.NewClient(&redis.Options{
+        Addr:     addr,
+        Password: password,
+        DB:       0,
+    })
+    
+    return &CacheService{client: client}
+}
+
+func (cs *CacheService) Set(key string, value interface{}, expiration time.Duration) error {
+    return cs.client.Set(context.Background(), key, value, expiration).Err()
+}
+
+func (cs *CacheService) Get(key string) (string, error) {
+    return cs.client.Get(context.Background(), key).Result()
+}
+
+func (cs *CacheService) Delete(key string) error {
+    return cs.client.Del(context.Background(), key).Err()
+}
+
+// Session管理
+func SessionMiddleware(store sessions.Store) gin.HandlerFunc {
+    return func(c *gin.Context) {
+        session, _ := store.Get(c.Request, "session-name")
+        c.Set("session", session)
+        
+        c.Next()
+        
+        session.Save(c.Request, c.Writer)
+    }
+}
+```
+
+## 5.4 性能优化与安全
+
+### 5.4.1 性能优化技巧
+```go
+// 数据库连接池优化
+func setupDatabase() *sql.DB {
+    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
+    if err != nil {
+        log.Fatal(err)
+    }
+    
+    // 连接池配置
+    db.SetMaxOpenConns(25)
+    db.SetMaxIdleConns(25)
+    db.SetConnMaxLifetime(5 * time.Minute)
+    
+    return db
+}
+
+// 响应压缩
+func CompressionMiddleware() gin.HandlerFunc {
+    return gin.Gzip(gin.DefaultCompression)
+}
+
+// 静态资源缓存
+func StaticCacheMiddleware() gin.HandlerFunc {
+    return func(c *gin.Context) {
+        if strings.HasPrefix(c.Request.URL.Path, "/static/") {
+            c.Header("Cache-Control", "public, max-age=31536000")
+        }
+        c.Next()
+    }
+}
+```
+
+### 5.4.2 安全防护措施
+```go
+// SQL注入防护
+func SafeQuery(db *sql.DB, query string, args ...interface{}) (*sql.Rows, error) {
+    // 使用参数化查询
+    return db.Query(query, args...)
+}
+
+// XSS防护
+func XSSMiddleware() gin.HandlerFunc {
+    return func(c *gin.Context) {
+        c.Header("X-XSS-Protection", "1; mode=block")
+        c.Header("X-Content-Type-Options", "nosniff")
+        c.Next()
+    }
+}
+
+// CSRF防护
+func CSRFMiddleware(secret string) gin.HandlerFunc {
+    return csrf.Middleware(csrf.Options{
+        Secret: secret,
+        ErrorFunc: func(c *gin.Context) {
+            c.JSON(403, gin.H{"error": "CSRF token验证失败"})
+            c.Abort()
+        },
+    })
+}
+```
+
+## 5.5 实战项目:电商平台
+
+### 项目功能模块
+- 用户管理(注册、登录、个人信息)
+- 商品管理(CRUD、分类、搜索)
+- 购物车功能
+- 订单管理
+- 支付集成
+- 后台管理系统
+
+### 技术架构
+```go
+// 项目结构
+ecommerce-platform/
+├── cmd/
+│   ├── api/                 # API服务器
+│   └── admin/              # 后台管理
+├── internal/
+│   ├── config/             # 配置管理
+│   ├── handler/            # HTTP处理器
+│   ├── middleware/         # 中间件
+│   ├── model/              # 数据模型
+│   ├── repository/         # 数据访问层
+│   ├── service/            # 业务逻辑层
+│   └── utils/              # 工具函数
+├── pkg/
+│   ├── auth/               # 认证模块
+│   ├── cache/              # 缓存模块
+│   ├── payment/            # 支付模块
+│   └── storage/            # 存储模块
+└── web/                    # 前端资源
+    ├── static/
+    └── templates/
+```
+
+### 核心业务逻辑
+```go
+// 购物车服务
+type CartService struct {
+    cartRepo    repository.CartRepository
+    productRepo repository.ProductRepository
+}
+
+func (cs *CartService) AddToCart(userID, productID uint, quantity int) error {
+    // 检查商品库存
+    product, err := cs.productRepo.FindByID(productID)
+    if err != nil {
+        return err
+    }
+    
+    if product.Stock < quantity {
+        return errors.New("库存不足")
+    }
+    
+    // 添加商品到购物车
+    return cs.cartRepo.AddItem(userID, productID, quantity)
+}
+
+// 订单服务
+type OrderService struct {
+    orderRepo   repository.OrderRepository
+    paymentRepo repository.PaymentRepository
+}
+
+func (os *OrderService) CreateOrder(userID uint, cartItems []model.CartItem) (*model.Order, error) {
+    // 计算总价
+    var totalAmount float64
+    for _, item := range cartItems {
+        totalAmount += item.Product.Price * float64(item.Quantity)
+    }
+    
+    // 创建订单
+    order := &model.Order{
+        UserID:      userID,
+        TotalAmount: totalAmount,
+        Status:      model.OrderStatusPending,
+    }
+    
+    return os.orderRepo.Create(order)
+}
+```
+
+## 特训评估标准
+
+### 技术掌握程度 (40%)
+- Web框架熟练度
+- 架构设计能力
+- 代码质量
+
+### 项目完成度 (30%)
+- 功能完整性
+- 用户体验
+- 文档质量
+
+### 性能与安全 (20%)
+- 响应速度
+- 安全措施
+- 错误处理
+
+### 创新与扩展 (10%)
+- 技术创新
+- 扩展性设计
+- 代码复用
+
+## 学习建议
+
+1. **循序渐进**:从基础功能开始,逐步增加复杂度
+2. **实践为主**:每个知识点都要动手编码
+3. **代码审查**:定期检查代码质量
+4. **性能测试**:关注应用性能指标
+5. **安全意识**:始终考虑安全防护
+
+这个Web开发特训章节将帮助您系统掌握Go语言Web开发的全套技能,为成为全栈开发工程师奠定坚实基础。

+ 39 - 0
examples/basics/hello-world.go

@@ -0,0 +1,39 @@
+package main
+
+import "fmt"
+
+func main() {
+    fmt.Println("Hello, World!")
+    
+    // 变量声明示例
+    var name string = "Go语言"
+    age := 25
+    score := 95.5
+    
+    fmt.Printf("姓名: %s, 年龄: %d, 分数: %.1f\n", name, age, score)
+    
+    // 控制结构示例
+    if age >= 18 {
+        fmt.Println("成年人")
+    } else {
+        fmt.Println("未成年人")
+    }
+    
+    // for循环示例
+    for i := 1; i <= 5; i++ {
+        fmt.Printf("循环次数: %d\n", i)
+    }
+    
+    // switch示例
+    grade := "B"
+    switch grade {
+    case "A":
+        fmt.Println("优秀")
+    case "B":
+        fmt.Println("良好")
+    case "C":
+        fmt.Println("及格")
+    default:
+        fmt.Println("不及格")
+    }
+}

+ 38 - 0
iot-base-station/.air.toml

@@ -0,0 +1,38 @@
+root = "."
+testdata_dir = "testdata"
+tmp_dir = "tmp"
+
+[build]
+  args_bin = []
+  bin = "./tmp/main"
+  cmd = "go build -o ./tmp/main ./cmd/server"
+  delay = 1000
+  exclude_dir = ["assets", "tmp", "vendor", "testdata", "simulations"]
+  exclude_file = []
+  exclude_regex = ["_test.go"]
+  exclude_unchanged = false
+  follow_symlink = false
+  full_bin = ""
+  include_dir = []
+  include_ext = ["go", "tpl", "tmpl", "html", "yaml", "yml"]
+  kill_delay = "0s"
+  log = "build-errors.log"
+  send_interrupt = false
+  stop_on_root = false
+
+[color]
+  app = ""
+  build = "yellow"
+  main = "magenta"
+  runner = "green"
+  watcher = "cyan"
+
+[log]
+  time = false
+
+[misc]
+  clean_on_exit = false
+
+[screen]
+  clear_on_rebuild = false
+  keep_scroll = true

+ 57 - 0
iot-base-station/Dockerfile

@@ -0,0 +1,57 @@
+# 构建阶段
+FROM golang:1.19-alpine AS builder
+
+# 设置工作目录
+WORKDIR /app
+
+# 安装必要的包
+RUN apk add --no-cache git ca-certificates tzdata
+
+# 复制go mod文件
+COPY go.mod go.sum ./
+
+# 下载依赖
+RUN go mod download
+
+# 复制源代码
+COPY . .
+
+# 构建应用
+RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o server cmd/server/main.go
+RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o gateway cmd/gateway/main.go
+RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o monitor cmd/monitor/main.go
+
+# 运行阶段
+FROM alpine:latest
+
+# 安装ca证书和时区数据
+RUN apk --no-cache add ca-certificates tzdata
+
+# 创建非root用户
+RUN addgroup -g 1001 -S appgroup && \
+    adduser -u 1001 -S appuser -G appgroup
+
+# 设置工作目录
+WORKDIR /app
+
+# 从构建阶段复制二进制文件
+COPY --from=builder /app/server .
+COPY --from=builder /app/gateway .
+COPY --from=builder /app/monitor .
+
+# 复制配置文件和静态资源
+COPY --from=builder /app/config ./config
+COPY --from=builder /app/web ./web
+
+# 创建必要的目录
+RUN mkdir -p logs uploads && \
+    chown -R appuser:appgroup /app
+
+# 切换到非root用户
+USER appuser
+
+# 暴露端口
+EXPOSE 8080 8081 8082
+
+# 默认启动服务器
+CMD ["./server"]

+ 478 - 0
iot-base-station/README.md

@@ -0,0 +1,478 @@
+# 物联网基站管理系统
+
+## 项目概述
+
+这是一个基于Go语言的物联网基站管理系统,支持多种通信协议(MQTT、CoAP、LoRaWAN),提供设备管理、数据处理、实时监控和智能告警等功能。
+
+## 系统架构
+
+```
+┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
+│   IoT设备       │    │   数据网关       │    │   管理平台       │
+│                 │    │                 │    │                 │
+│ ┌─────────────┐ │    │ ┌─────────────┐ │    │ ┌─────────────┐ │
+│ │ 传感器节点   │ │◄──►│ │ MQTT适配器   │ │◄──►│ │ 设备管理     │ │
+│ └─────────────┘ │    │ └─────────────┘ │    │ └─────────────┘ │
+│ ┌─────────────┐ │    │ ┌─────────────┐ │    │ ┌─────────────┐ │
+│ │ 执行器节点   │ │◄──►│ │ CoAP适配器   │ │◄──►│ │ 数据处理     │ │
+│ └─────────────┘ │    │ └─────────────┘ │    │ └─────────────┘ │
+│ ┌─────────────┐ │    │ ┌─────────────┐ │    │ ┌─────────────┐ │
+│ │ LoRa节点     │ │◄──►│ │ LoRa适配器   │ │◄──►│ │ 告警系统     │ │
+│ └─────────────┘ │    │ └─────────────┘ │    │ └─────────────┘ │
+└─────────────────┘    └─────────────────┘    └─────────────────┘
+```
+
+## 功能特性
+
+### 多协议支持
+- MQTT协议支持
+- CoAP协议支持
+- LoRaWAN协议支持
+- HTTP RESTful API
+- WebSocket实时通信
+
+### 设备管理
+- 设备注册与认证
+- 设备状态监控
+- 远程配置管理
+- OTA固件更新
+- 设备故障诊断
+
+### 数据处理
+- 实时数据采集
+- 数据清洗与预处理
+- 时序数据存储
+- 数据聚合与统计
+- 历史数据分析
+
+### 监控与告警
+- 实时监控仪表板
+- 自定义告警规则
+- 多级告警机制
+- 多渠道通知
+- 告警抑制与恢复
+
+## 技术栈
+
+### 后端技术
+- **语言**: Go 1.19+
+- **Web框架**: Gin
+- **消息队列**: NATS
+- **时序数据库**: InfluxDB
+- **关系数据库**: PostgreSQL
+- **缓存**: Redis
+- **监控**: Prometheus + Grafana
+
+### 通信协议
+- **MQTT**: Eclipse Paho
+- **CoAP**: go-coap
+- **LoRaWAN**: ChirpStack
+- **HTTP**: RESTful API
+- **WebSocket**: 实时通信
+
+### 前端技术
+- **框架**: React
+- **图表库**: Chart.js
+- **UI组件**: Ant Design
+- **实时通信**: WebSocket
+
+### 部署技术
+- **容器化**: Docker
+- **编排**: Docker Compose
+- **CI/CD**: GitLab CI
+- **监控**: Prometheus + Grafana
+
+## 快速开始
+
+### 环境要求
+- Go 1.19+
+- Docker & Docker Compose
+- Node.js 16+ (前端开发)
+- Git
+
+### 安装步骤
+
+1. **克隆项目**
+```bash
+git clone https://github.com/your-username/iot-base-station.git
+cd iot-base-station
+```
+
+2. **启动依赖服务**
+```bash
+# 启动基础服务(不包括应用)
+docker-compose up -d postgres influxdb redis nats mqtt
+
+# 等待服务就绪
+docker-compose ps
+```
+
+3. **安装Go依赖**
+```bash
+go mod download
+go mod tidy
+```
+
+4. **初始化数据库**
+```bash
+# 创建PostgreSQL数据库
+docker-compose exec postgres psql -U postgres -c "CREATE DATABASE iot_base_station;"
+
+# 运行数据库迁移
+go run cmd/migrate/main.go up
+```
+
+5. **运行服务**
+```bash
+# 方式1:分别运行(推荐用于开发)
+# 终端1:启动主服务器
+CONFIG_PATH=config/config.dev.yaml go run cmd/server/main.go
+
+# 终端2:启动数据网关
+CONFIG_PATH=config/config.dev.yaml go run cmd/gateway/main.go
+
+# 终端3:启动监控服务
+CONFIG_PATH=config/config.dev.yaml go run cmd/monitor/main.go
+
+# 方式2:使用Docker Compose(推荐用于测试)
+docker-compose up -d
+```
+
+6. **运行设备模拟器(可选)**
+```bash
+# 新终端窗口
+go run simulations/main.go -broker=tcp://localhost:1883 -count=5 -interval=30s
+```
+
+7. **访问应用**
+- 管理平台: http://localhost:8080
+- API文档: http://localhost:8080/swagger/index.html
+- 监控面板: http://localhost:3000 (Grafana)
+
+## 本地开发调试
+
+详细的本地开发调试指南请参考:[本地开发调试文档](docs/local-development.md)
+
+### 快速调试步骤
+
+1. **创建开发配置**
+```bash
+cp config/config.yaml config/config.dev.yaml
+# 编辑config/config.dev.yaml,设置debug模式
+```
+
+2. **使用热重载**
+```bash
+# 安装Air热重载工具
+go install github.com/cosmtrek/air@latest
+
+# 启动热重载
+air -c .air.toml
+```
+
+3. **调试API**
+```bash
+# 注册测试设备
+curl -X POST http://localhost:8080/api/v1/devices \
+  -H "Content-Type: application/json" \
+  -d '{
+    "name": "测试温度传感器",
+    "type": "temperature_sensor",
+    "protocol": "mqtt"
+  }'
+
+# 获取设备列表
+curl -X GET http://localhost:8080/api/v1/devices
+```
+
+4. **测试MQTT连接**
+```bash
+# 订阅主题
+docker-compose exec mqtt mosquitto_sub -h localhost -t "iot/data/+/+"
+
+# 发布测试数据
+docker-compose exec mqtt mosquitto_pub -h localhost -t "iot/data/test/temperature" -m '{"temperature": 25.5}'
+```
+
+## 项目结构
+
+```
+iot-base-station/
+├── README.md                 # 项目说明
+├── go.mod                    # 依赖管理
+├── config/                   # 配置文件
+│   ├── config.yaml          # 应用配置
+│   └── devices.yaml         # 设备配置
+├── cmd/                      # 应用入口
+│   ├── server/              # 主服务器
+│   │   └── main.go
+│   ├── gateway/             # 数据网关
+│   │   └── main.go
+│   └── monitor/             # 监控服务
+│       └── main.go
+├── internal/                 # 内部包
+│   ├── config/              # 配置管理
+│   │   └── config.go
+│   ├── device/              # 设备管理
+│   │   ├── device.go
+│   │   └── manager.go
+│   ├── protocol/            # 协议实现
+│   │   ├── mqtt/
+│   │   ├── coap/
+│   │   └── lora/
+│   ├── storage/             # 数据存储
+│   │   ├── influxdb.go
+│   │   └── postgresql.go
+│   ├── analytics/           # 数据分析
+│   │   ├── processor.go
+│   │   └── aggregator.go
+│   └── notification/        # 通知服务
+│       ├── alert.go
+│       └── notifier.go
+├── pkg/                      # 公共包
+│   ├── mqtt/                # MQTT客户端
+│   │   └── client.go
+│   ├── coap/                # CoAP客户端
+│   │   └── client.go
+│   ├── lora/                # LoRaWAN客户端
+│   │   └── client.go
+│   ├── database/            # 数据库连接
+│   │   └── connection.go
+│   └── security/            # 安全模块
+│       └── auth.go
+├── web/                      # Web界面
+│   ├── static/              # 静态资源
+│   └── templates/           # 模板文件
+├── scripts/                  # 脚本文件
+│   ├── setup.sh             # 环境设置
+│   └── deploy.sh            # 部署脚本
+├── docs/                     # 文档
+│   ├── api.md               # API文档
+│   ├── architecture.md      # 架构文档
+│   └── deployment.md        # 部署文档
+├── tests/                    # 测试文件
+├── simulations/              # 模拟器
+│   ├── devices/             # 设备模拟器
+│   └── network/             # 网络模拟器
+└── docker-compose.yml        # Docker配置
+```
+
+## API文档
+
+### 设备管理API
+
+#### 注册设备
+```http
+POST /api/v1/devices
+Content-Type: application/json
+
+{
+  "name": "温度传感器01",
+  "type": "temperature_sensor",
+  "protocol": "mqtt",
+  "metadata": {
+    "location": "机房A",
+    "model": "DHT22"
+  }
+}
+```
+
+#### 获取设备列表
+```http
+GET /api/v1/devices?page=1&page_size=10&type=temperature_sensor
+```
+
+#### 获取设备详情
+```http
+GET /api/v1/devices/{device_id}
+```
+
+#### 更新设备配置
+```http
+PUT /api/v1/devices/{device_id}/config
+Content-Type: application/json
+
+{
+  "report_interval": 30,
+  "threshold": {
+    "min": 10,
+    "max": 35
+  }
+}
+```
+
+### 数据查询API
+
+#### 获取实时数据
+```http
+GET /api/v1/data/realtime?device_id={device_id}&metric=temperature
+```
+
+#### 获取历史数据
+```http
+GET /api/v1/data/history?device_id={device_id}&metric=temperature&start=2023-01-01T00:00:00Z&end=2023-01-02T00:00:00Z
+```
+
+### 告警管理API
+
+#### 创建告警规则
+```http
+POST /api/v1/alerts/rules
+Content-Type: application/json
+
+{
+  "name": "温度过高告警",
+  "description": "当温度超过35度时触发告警",
+  "condition": "temperature > 35",
+  "severity": "warning",
+  "actions": [
+    {
+      "type": "email",
+      "config": {
+        "to": ["[email protected]"]
+      }
+    }
+  ]
+}
+```
+
+## 开发指南
+
+### 添加新协议支持
+
+1. 在`internal/protocol/`目录下创建新协议目录
+2. 实现`ProtocolAdapter`接口
+3. 在网关服务中注册新适配器
+4. 添加配置选项
+5. 编写测试用例
+
+```go
+// 协议适配器接口
+type ProtocolAdapter interface {
+    Name() string
+    Start() error
+    Stop() error
+    HandleMessage(msg Message) error
+}
+
+// 新协议实现示例
+type CustomProtocolAdapter struct {
+    config CustomProtocolConfig
+}
+
+func (c *CustomProtocolAdapter) Name() string {
+    return "custom"
+}
+
+func (c *CustomProtocolAdapter) Start() error {
+    // 实现启动逻辑
+}
+
+func (c *CustomProtocolAdapter) Stop() error {
+    // 实现停止逻辑
+}
+
+func (c *CustomProtocolAdapter) HandleMessage(msg Message) error {
+    // 实现消息处理逻辑
+}
+```
+
+### 添加新数据处理规则
+
+1. 在`internal/analytics/`目录下创建规则文件
+2. 实现`ProcessingRule`接口
+3. 在数据处理器中注册新规则
+4. 添加配置选项
+5. 编写测试用例
+
+```go
+// 处理规则接口
+type ProcessingRule interface {
+    Name() string
+    Apply(data Message) (ProcessedData, error)
+}
+
+// 新规则实现示例
+type CustomProcessingRule struct {
+    config CustomRuleConfig
+}
+
+func (c *CustomProcessingRule) Name() string {
+    return "custom_rule"
+}
+
+func (c *CustomProcessingRule) Apply(data Message) (ProcessedData, error) {
+    // 实现数据处理逻辑
+}
+```
+
+## 部署指南
+
+### Docker部署
+
+1. **构建镜像**
+```bash
+docker build -t iot-base-station .
+```
+
+2. **使用Docker Compose部署**
+```bash
+docker-compose up -d
+```
+
+3. **查看服务状态**
+```bash
+docker-compose ps
+```
+
+### Kubernetes部署
+
+1. **创建命名空间**
+```bash
+kubectl create namespace iot-base-station
+```
+
+2. **部署应用**
+```bash
+kubectl apply -f k8s/
+```
+
+3. **查看部署状态**
+```bash
+kubectl get pods -n iot-base-station
+```
+
+## 监控与运维
+
+### 系统监控
+
+- **应用指标**: Prometheus + Grafana
+- **日志收集**: ELK Stack
+- **链路追踪**: Jaeger
+- **健康检查**: 自定义健康检查端点
+
+### 告警配置
+
+- **系统告警**: 资源使用率、服务可用性
+- **业务告警**: 设备离线、数据异常
+- **安全告警**: 异常访问、认证失败
+
+## 贡献指南
+
+1. Fork 项目
+2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
+3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
+4. 推送到分支 (`git push origin feature/AmazingFeature`)
+5. 打开 Pull Request
+
+## 许可证
+
+本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情
+
+## 联系方式
+
+如有问题或建议,请提交 Issue 或联系项目维护者
+
+---
+
+**注意**: 这是一个学习项目,不建议直接用于生产环境。在生产环境中使用前,请确保进行充分的安全评估和性能测试。

+ 104 - 0
iot-base-station/cmd/migrate/main.go

@@ -0,0 +1,104 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"os"
+
+	"iot-base-station/internal/config"
+	"iot-base-station/pkg/database"
+
+	"github.com/golang-migrate/migrate/v4"
+	_ "github.com/golang-migrate/migrate/v4/database/postgres"
+	_ "github.com/golang-migrate/migrate/v4/source/file"
+)
+
+func main() {
+	var (
+		action = flag.String("action", "", "Migration action: up, down, version, force")
+		step   = flag.Int("step", 0, "Number of steps to migrate (for up/down)")
+		version = flag.Int("version", 0, "Target version (for force)")
+	)
+	flag.Parse()
+
+	if *action == "" {
+		fmt.Println("Usage: migrate -action=<up|down|version|force> [-step=N] [-version=N]")
+		os.Exit(1)
+	}
+
+	// 加载配置
+	cfg, err := config.LoadConfig("config/config.yaml")
+	if err != nil {
+		log.Fatalf("Failed to load config: %v", err)
+	}
+
+	// 连接数据库
+	db, err := database.InitPostgres(cfg.Database.Postgres)
+	if err != nil {
+		log.Fatalf("Failed to connect to database: %v", err)
+	}
+	defer db.Close()
+
+	// 创建迁移实例
+	m, err := migrate.New(
+		"file://migrations",
+		fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable",
+			cfg.Database.Postgres.User,
+			cfg.Database.Postgres.Password,
+			cfg.Database.Postgres.Host,
+			cfg.Database.Postgres.Port,
+			cfg.Database.Postgres.DBName,
+		),
+	)
+	if err != nil {
+		log.Fatalf("Failed to create migration instance: %v", err)
+	}
+	defer m.Close()
+
+	// 执行迁移
+	switch *action {
+	case "up":
+		if *step > 0 {
+			if err := m.Steps(*step); err != nil {
+				log.Fatalf("Failed to migrate up: %v", err)
+			}
+		} else {
+			if err := m.Up(); err != nil && err != migrate.ErrNoChange {
+				log.Fatalf("Failed to migrate up: %v", err)
+			}
+		}
+		fmt.Println("Migration up completed successfully")
+
+	case "down":
+		if *step > 0 {
+			if err := m.Steps(-*step); err != nil {
+				log.Fatalf("Failed to migrate down: %v", err)
+			}
+		} else {
+			if err := m.Down(); err != nil && err != migrate.ErrNoChange {
+				log.Fatalf("Failed to migrate down: %v", err)
+			}
+		}
+		fmt.Println("Migration down completed successfully")
+
+	case "version":
+		version, dirty, err := m.Version()
+		if err != nil {
+			log.Fatalf("Failed to get version: %v", err)
+		}
+		fmt.Printf("Current version: %d, dirty: %v\n", version, dirty)
+
+	case "force":
+		if *version < 0 {
+			log.Fatal("Version must be specified for force action")
+		}
+		if err := m.Force(*version); err != nil {
+			log.Fatalf("Failed to force version: %v", err)
+		}
+		fmt.Printf("Forced version to %d\n", *version)
+
+	default:
+		log.Fatalf("Unknown action: %s", *action)
+	}
+}

+ 236 - 0
iot-base-station/cmd/server/main.go

@@ -0,0 +1,236 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"os"
+	"os/signal"
+	"syscall"
+	"time"
+
+	"iot-base-station/internal/config"
+	"iot-base-station/internal/device"
+	"iot-base-station/internal/analytics"
+	"iot-base-station/internal/notification"
+	"iot-base-station/pkg/database"
+	"iot-base-station/pkg/security"
+
+	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
+)
+
+func main() {
+	// 加载配置
+	cfg, err := config.LoadConfig("config/config.yaml")
+	if err != nil {
+		log.Fatalf("Failed to load config: %v", err)
+	}
+
+	// 初始化日志
+	logger, err := initLogger(cfg.Logging)
+	if err != nil {
+		log.Fatalf("Failed to initialize logger: %v", err)
+	}
+	defer logger.Sync()
+
+	// 初始化数据库
+	postgresDB, err := database.InitPostgres(cfg.Database.Postgres)
+	if err != nil {
+		logger.Fatal("Failed to initialize PostgreSQL", zap.Error(err))
+	}
+	defer postgresDB.Close()
+
+	influxDB, err := database.InitInfluxDB(cfg.Database.InfluxDB)
+	if err != nil {
+		logger.Fatal("Failed to initialize InfluxDB", zap.Error(err))
+	}
+	defer influxDB.Close()
+
+	// 初始化Redis
+	redisClient, err := database.InitRedis(cfg.Redis)
+	if err != nil {
+		logger.Fatal("Failed to initialize Redis", zap.Error(err))
+	}
+	defer redisClient.Close()
+
+	// 初始化JWT服务
+	jwtService := security.NewJWTService(cfg.JWT.Secret, cfg.JWT.Expire)
+
+	// 初始化设备管理器
+	deviceManager := device.NewManager(postgresDB, redisClient, logger)
+
+	// 初始化数据处理器
+	dataProcessor := analytics.NewProcessor(influxDB, logger)
+
+	// 初始化通知服务
+	notifier := notification.NewNotifier(cfg.Notification, logger)
+
+	// 初始化告警系统
+	alertManager := notification.NewAlertManager(cfg.Alert, notifier, logger)
+
+	// 设置Gin模式
+	gin.SetMode(cfg.Server.Mode)
+
+	// 创建Gin引擎
+	r := gin.New()
+
+	// 添加中间件
+	r.Use(gin.Logger())
+	r.Use(gin.Recovery())
+	r.Use(corsMiddleware())
+
+	// 设置路由
+	setupRoutes(r, deviceManager, dataProcessor, alertManager, jwtService, logger)
+
+	// 启动后台服务
+	go startBackgroundServices(deviceManager, dataProcessor, alertManager, cfg, logger)
+
+	// 创建HTTP服务器
+	srv := &http.Server{
+		Addr:         ":" + cfg.Server.Port,
+		Handler:      r,
+		ReadTimeout:  time.Duration(cfg.Server.ReadTimeout) * time.Second,
+		WriteTimeout: time.Duration(cfg.Server.WriteTimeout) * time.Second,
+	}
+
+	// 启动服务器
+	go func() {
+		logger.Info("Starting server", zap.String("port", cfg.Server.Port))
+		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+			logger.Fatal("Failed to start server", zap.Error(err))
+		}
+	}()
+
+	// 等待中断信号
+	quit := make(chan os.Signal, 1)
+	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+	<-quit
+
+	logger.Info("Shutting down server...")
+
+	// 优雅关闭
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+	defer cancel()
+
+	if err := srv.Shutdown(ctx); err != nil {
+		logger.Fatal("Server forced to shutdown", zap.Error(err))
+	}
+
+	logger.Info("Server exited")
+}
+
+func setupRoutes(r *gin.Engine, 
+	deviceManager *device.Manager,
+	dataProcessor *analytics.Processor,
+	alertManager *notification.AlertManager,
+	jwtService *security.JWTService,
+	logger *zap.Logger) {
+	
+	// 健康检查
+	r.GET("/health", func(c *gin.Context) {
+		c.JSON(200, gin.H{"status": "ok"})
+	})
+
+	// API路由组
+	api := r.Group("/api/v1")
+	{
+		// 设备管理路由
+		deviceGroup := api.Group("/devices")
+		{
+			deviceGroup.POST("", deviceManager.CreateDevice)
+			deviceGroup.GET("", deviceManager.ListDevices)
+			deviceGroup.GET("/:id", deviceManager.GetDevice)
+			deviceGroup.PUT("/:id", deviceManager.UpdateDevice)
+			deviceGroup.DELETE("/:id", deviceManager.DeleteDevice)
+			deviceGroup.PUT("/:id/config", deviceManager.UpdateDeviceConfig)
+			deviceGroup.POST("/:id/firmware", deviceManager.UpdateFirmware)
+		}
+
+		// 数据查询路由
+		dataGroup := api.Group("/data")
+		{
+			dataGroup.GET("/realtime", dataProcessor.GetRealtimeData)
+			dataGroup.GET("/history", dataProcessor.GetHistoryData)
+			dataGroup.GET("/statistics", dataProcessor.GetStatistics)
+		}
+
+		// 告警管理路由
+		alertGroup := api.Group("/alerts")
+		{
+			alertGroup.GET("/rules", alertManager.ListRules)
+			alertGroup.POST("/rules", alertManager.CreateRule)
+			alertGroup.GET("/rules/:id", alertManager.GetRule)
+			alertGroup.PUT("/rules/:id", alertManager.UpdateRule)
+			alertGroup.DELETE("/rules/:id", alertManager.DeleteRule)
+			alertGroup.GET("", alertManager.ListAlerts)
+		}
+
+		// 认证路由
+		authGroup := api.Group("/auth")
+		{
+			authGroup.POST("/login", func(c *gin.Context) {
+				// 实现登录逻辑
+			})
+			authGroup.POST("/refresh", func(c *gin.Context) {
+				// 实现令牌刷新逻辑
+			})
+		}
+	}
+
+	// WebSocket路由
+	r.GET("/ws", func(c *gin.Context) {
+		// 实现WebSocket连接
+	})
+}
+
+func startBackgroundServices(
+	deviceManager *device.Manager,
+	dataProcessor *analytics.Processor,
+	alertManager *notification.AlertManager,
+	cfg *config.Config,
+	logger *zap.Logger) {
+	
+	// 启动设备状态检查
+	go deviceManager.StartStatusCheck()
+
+	// 启动数据处理器
+	go dataProcessor.Start()
+
+	// 启动告警检查
+	go alertManager.Start()
+
+	logger.Info("Background services started")
+}
+
+func corsMiddleware() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		c.Header("Access-Control-Allow-Origin", "*")
+		c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
+		c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
+		
+		if c.Request.Method == "OPTIONS" {
+			c.AbortWithStatus(204)
+			return
+		}
+		
+		c.Next()
+	}
+}
+
+func initLogger(logConfig config.LoggingConfig) (*zap.Logger, error) {
+	var logger *zap.Logger
+	var err error
+
+	if logConfig.Level == "debug" {
+		logger, err = zap.NewDevelopment()
+	} else {
+		logger, err = zap.NewProduction()
+	}
+
+	if err != nil {
+		return nil, err
+	}
+
+	return logger, nil
+}

+ 88 - 0
iot-base-station/config/config.yaml

@@ -0,0 +1,88 @@
+server:
+  port: "8080"
+  mode: "debug"  # debug, release, test
+  read_timeout: 60
+  write_timeout: 60
+
+database:
+  postgres:
+    host: "localhost"
+    port: "5432"
+    user: "postgres"
+    password: "postgres"
+    dbname: "iot_base_station"
+    max_open_conns: 25
+    max_idle_conns: 5
+    conn_max_lifetime: 300
+  
+  influxdb:
+    url: "http://localhost:8086"
+    token: "influxdb-token"
+    org: "iot-org"
+    bucket: "iot-data"
+    timeout: 10
+
+redis:
+  host: "localhost"
+  port: "6379"
+  password: ""
+  db: 0
+  pool_size: 10
+
+nats:
+  url: "nats://localhost:4222"
+  subject_prefix: "iot"
+
+mqtt:
+  broker: "tcp://localhost:1883"
+  client_id: "iot-gateway"
+  username: ""
+  password: ""
+  keep_alive: 60
+  qos: 1
+
+coap:
+  address: ":5683"
+  path: "/iot"
+  max_message_size: 1024
+
+lora:
+  server_url: "http://localhost:8080"
+  application_id: "iot-app"
+  access_key: "lora-access-key"
+
+jwt:
+  secret: "iot-jwt-secret"
+  expire: 86400  # 24 hours
+
+alert:
+  enabled: true
+  check_interval: 30  # seconds
+  max_alerts_per_device: 10
+  suppression_window: 300  # seconds
+
+notification:
+  email:
+    enabled: false
+    smtp_host: "smtp.example.com"
+    smtp_port: 587
+    username: "[email protected]"
+    password: "email-password"
+    from: "[email protected]"
+  
+  webhook:
+    enabled: true
+    url: "http://localhost:8081/webhook"
+    timeout: 10
+
+monitoring:
+  enabled: true
+  metrics_path: "/metrics"
+  health_check_path: "/health"
+
+logging:
+  level: "info"
+  output: "logs/app.log"
+  max_size: 100  # MB
+  max_backups: 3
+  max_age: 28  # days

+ 68 - 0
iot-base-station/config/mosquitto.conf

@@ -0,0 +1,68 @@
+# Mosquitto MQTT Broker配置文件
+
+# 基本配置
+pid_file /var/run/mosquitto.pid
+persistence true
+persistence_location /mosquitto/data/
+log_dest file /mosquitto/log/mosquitto.log
+log_type error
+log_type warning
+log_type notice
+log_type information
+
+# 网络配置
+listener 1883
+protocol mqtt
+
+# WebSocket支持
+listener 9001
+protocol websockets
+
+# 认证配置(可选,根据需要启用)
+# allow_anonymous false
+# password_file /mosquitto/config/passwd
+
+# 访问控制(可选,根据需要启用)
+# acl_file /mosquitto/config/acl
+
+# 连接配置
+max_connections 1000
+max_inflight_messages 20
+max_queued_messages 100
+message_size_limit 0
+
+# 保持连接
+keepalive_interval 60
+retry_interval 20
+sys_interval 10
+
+# 日志配置
+log_timestamp true
+log_timestamp_format %Y-%m-%dT%H:%M:%S
+
+# 安全配置(可选,根据需要启用)
+# cafile /mosquitto/certs/ca.crt
+# certfile /mosquitto/certs/server.crt
+# keyfile /mosquitto/certs/server.key
+# require_certificate false
+# use_identity_as_username false
+
+# 桥接配置(可选,根据需要启用)
+# connection bridge-01
+# address remote.mqtt.broker:1883
+# topic iot/# both 0
+
+# 自动保存间隔
+autosave_interval 1800
+
+# 客户端过期时间
+persistent_client_expiration 2h
+
+# 升级QoS
+upgrade_outgoing_qos false
+
+# 最大保留消息数
+max_retained_messages 100
+
+# 主题别名最大值
+max_topic_alias 10

+ 195 - 0
iot-base-station/docker-compose-without-redis.yml

@@ -0,0 +1,195 @@
+version: '3.8'
+
+services:
+  # 主应用服务
+  app:
+    build: .
+    ports:
+      - "8080:8080"
+    environment:
+      - DB_HOST=postgres
+      - DB_PORT=5432
+      - DB_USER=postgres
+      - DB_PASSWORD=postgres
+      - DB_NAME=iot_base_station
+      - INFLUXDB_URL=http://influxdb:8086
+      - INFLUXDB_TOKEN=influxdb-token
+      - INFLUXDB_ORG=iot-org
+      - INFLUXDB_BUCKET=iot-data
+      - REDIS_HOST=host.docker.internal  # 使用主机上的Redis
+      - REDIS_PORT=6379
+      - NATS_URL=nats://nats:4222
+      - MQTT_BROKER=tcp://mqtt:1883
+    depends_on:
+      - postgres
+      - influxdb
+      - nats
+      - mqtt
+    volumes:
+      - ./logs:/app/logs
+      - ./uploads:/app/uploads
+    networks:
+      - iot-network
+    extra_hosts:
+      - "host.docker.internal:host-gateway"  # 允许访问主机服务
+
+  # 数据网关服务
+  gateway:
+    build: .
+    command: ["go", "run", "cmd/gateway/main.go"]
+    ports:
+      - "8081:8081"
+    environment:
+      - DB_HOST=postgres
+      - DB_PORT=5432
+      - DB_USER=postgres
+      - DB_PASSWORD=postgres
+      - DB_NAME=iot_base_station
+      - INFLUXDB_URL=http://influxdb:8086
+      - INFLUXDB_TOKEN=influxdb-token
+      - INFLUXDB_ORG=iot-org
+      - INFLUXDB_BUCKET=iot-data
+      - REDIS_HOST=host.docker.internal  # 使用主机上的Redis
+      - REDIS_PORT=6379
+      - NATS_URL=nats://nats:4222
+      - MQTT_BROKER=tcp://mqtt:1883
+    depends_on:
+      - postgres
+      - influxdb
+      - nats
+      - mqtt
+    volumes:
+      - ./logs:/app/logs
+    networks:
+      - iot-network
+    extra_hosts:
+      - "host.docker.internal:host-gateway"  # 允许访问主机服务
+
+  # 监控服务
+  monitor:
+    build: .
+    command: ["go", "run", "cmd/monitor/main.go"]
+    ports:
+      - "8082:8082"
+    environment:
+      - DB_HOST=postgres
+      - DB_PORT=5432
+      - DB_USER=postgres
+      - DB_PASSWORD=postgres
+      - DB_NAME=iot_base_station
+      - INFLUXDB_URL=http://influxdb:8086
+      - INFLUXDB_TOKEN=influxdb-token
+      - INFLUXDB_ORG=iot-org
+      - INFLUXDB_BUCKET=iot-data
+      - REDIS_HOST=host.docker.internal  # 使用主机上的Redis
+      - REDIS_PORT=6379
+    depends_on:
+      - postgres
+      - influxdb
+    volumes:
+      - ./logs:/app/logs
+    networks:
+      - iot-network
+    extra_hosts:
+      - "host.docker.internal:host-gateway"  # 允许访问主机服务
+
+  # PostgreSQL数据库
+  postgres:
+    image: postgres:14
+    environment:
+      - POSTGRES_USER=postgres
+      - POSTGRES_PASSWORD=postgres
+      - POSTGRES_DB=iot_base_station
+    ports:
+      - "5432:5432"
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+      - ./scripts/init-postgres.sql:/docker-entrypoint-initdb.d/init-postgres.sql
+    networks:
+      - iot-network
+
+  # InfluxDB时序数据库
+  influxdb:
+    image: influxdb:2.0
+    environment:
+      - DOCKER_INFLUXDB_INIT_MODE=setup
+      - DOCKER_INFLUXDB_INIT_USERNAME=admin
+      - DOCKER_INFLUXDB_INIT_PASSWORD=adminpassword
+      - DOCKER_INFLUXDB_INIT_ORG=iot-org
+      - DOCKER_INFLUXDB_INIT_BUCKET=iot-data
+      - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=influxdb-token
+    ports:
+      - "8086:8086"
+    volumes:
+      - influxdb_data:/var/lib/influxdb2
+    networks:
+      - iot-network
+
+  # NATS消息队列
+  nats:
+    image: nats:2-alpine
+    ports:
+      - "4222:4222"
+      - "8222:8222"  # HTTP监控端口
+    command: ["-js", "-m", "8222"]  # 启用JetStream和监控
+    networks:
+      - iot-network
+
+  # MQTT代理
+  mqtt:
+    image: eclipse-mosquitto:2
+    ports:
+      - "1883:1883"
+      - "9001:9001"  # WebSocket端口
+    volumes:
+      - ./config/mosquitto.conf:/mosquitto/config/mosquitto.conf
+      - mqtt_data:/mosquitto/data
+      - mqtt_logs:/mosquitto/log
+    networks:
+      - iot-network
+
+  # Grafana监控面板
+  grafana:
+    image: grafana/grafana:latest
+    ports:
+      - "3000:3000"
+    environment:
+      - GF_SECURITY_ADMIN_PASSWORD=admin
+    volumes:
+      - grafana_data:/var/lib/grafana
+      - ./config/grafana/dashboards:/etc/grafana/provisioning/dashboards
+      - ./config/grafana/datasources:/etc/grafana/provisioning/datasources
+    depends_on:
+      - influxdb
+    networks:
+      - iot-network
+
+  # Prometheus监控
+  prometheus:
+    image: prom/prometheus:latest
+    ports:
+      - "9090:9090"
+    volumes:
+      - ./config/prometheus.yml:/etc/prometheus/prometheus.yml
+      - prometheus_data:/prometheus
+    command:
+      - '--config.file=/etc/prometheus/prometheus.yml'
+      - '--storage.tsdb.path=/prometheus'
+      - '--web.console.libraries=/etc/prometheus/console_libraries'
+      - '--web.console.templates=/etc/prometheus/consoles'
+      - '--storage.tsdb.retention.time=200h'
+      - '--web.enable-lifecycle'
+    networks:
+      - iot-network
+
+volumes:
+  postgres_data:
+  influxdb_data:
+  mqtt_data:
+  mqtt_logs:
+  grafana_data:
+  prometheus_data:
+
+networks:
+  iot-network:
+    driver: bridge

+ 231 - 0
iot-base-station/docker-compose.yml

@@ -0,0 +1,231 @@
+version: '3.8'
+
+services:
+  # 主应用服务
+  app:
+    build: .
+    ports:
+      - "8080:8080"
+    environment:
+      - DB_HOST=postgres
+      - DB_PORT=5432
+      - DB_USER=postgres
+      - DB_PASSWORD=postgres
+      - DB_NAME=iot_base_station
+      - INFLUXDB_URL=http://influxdb:8086
+      - INFLUXDB_TOKEN=influxdb-token
+      - INFLUXDB_ORG=iot-org
+      - INFLUXDB_BUCKET=iot-data
+      - REDIS_HOST=redis
+      - REDIS_PORT=6379
+      - NATS_URL=nats://nats:4222
+      - MQTT_BROKER=tcp://mqtt:1883
+    depends_on:
+      - postgres
+      - influxdb
+      - redis
+      - nats
+      - mqtt
+    volumes:
+      - ./logs:/app/logs
+      - ./uploads:/app/uploads
+    networks:
+      - iot-network
+
+  # 数据网关服务
+  gateway:
+    build: .
+    command: ["go", "run", "cmd/gateway/main.go"]
+    ports:
+      - "8081:8081"
+    environment:
+      - DB_HOST=postgres
+      - DB_PORT=5432
+      - DB_USER=postgres
+      - DB_PASSWORD=postgres
+      - DB_NAME=iot_base_station
+      - INFLUXDB_URL=http://influxdb:8086
+      - INFLUXDB_TOKEN=influxdb-token
+      - INFLUXDB_ORG=iot-org
+      - INFLUXDB_BUCKET=iot-data
+      - REDIS_HOST=redis
+      - REDIS_PORT=6379
+      - NATS_URL=nats://nats:4222
+      - MQTT_BROKER=tcp://mqtt:1883
+    depends_on:
+      - postgres
+      - influxdb
+      - redis
+      - nats
+      - mqtt
+    volumes:
+      - ./logs:/app/logs
+    networks:
+      - iot-network
+
+  # 监控服务
+  monitor:
+    build: .
+    command: ["go", "run", "cmd/monitor/main.go"]
+    ports:
+      - "8082:8082"
+    environment:
+      - DB_HOST=postgres
+      - DB_PORT=5432
+      - DB_USER=postgres
+      - DB_PASSWORD=postgres
+      - DB_NAME=iot_base_station
+      - INFLUXDB_URL=http://influxdb:8086
+      - INFLUXDB_TOKEN=influxdb-token
+      - INFLUXDB_ORG=iot-org
+      - INFLUXDB_BUCKET=iot-data
+      - REDIS_HOST=redis
+      - REDIS_PORT=6379
+    depends_on:
+      - postgres
+      - influxdb
+      - redis
+    volumes:
+      - ./logs:/app/logs
+    networks:
+      - iot-network
+
+  # PostgreSQL数据库
+  postgres:
+    image: postgres:14
+    environment:
+      - POSTGRES_USER=postgres
+      - POSTGRES_PASSWORD=postgres
+      - POSTGRES_DB=iot_base_station
+    ports:
+      - "5432:5432"
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+      - ./scripts/init-postgres.sql:/docker-entrypoint-initdb.d/init-postgres.sql
+    networks:
+      - iot-network
+
+  # InfluxDB时序数据库
+  influxdb:
+    image: influxdb:2.0
+    environment:
+      - DOCKER_INFLUXDB_INIT_MODE=setup
+      - DOCKER_INFLUXDB_INIT_USERNAME=admin
+      - DOCKER_INFLUXDB_INIT_PASSWORD=adminpassword
+      - DOCKER_INFLUXDB_INIT_ORG=iot-org
+      - DOCKER_INFLUXDB_INIT_BUCKET=iot-data
+      - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=influxdb-token
+    ports:
+      - "8086:8086"
+    volumes:
+      - influxdb_data:/var/lib/influxdb2
+    networks:
+      - iot-network
+
+  # Redis缓存
+  redis:
+    image: redis:6-alpine
+    ports:
+      - "6379:6379"
+    volumes:
+      - redis_data:/data
+    networks:
+      - iot-network
+
+  # NATS消息队列
+  nats:
+    image: nats:2-alpine
+    ports:
+      - "4222:4222"
+      - "8222:8222"  # HTTP监控端口
+    command: ["-js", "-m", "8222"]  # 启用JetStream和监控
+    networks:
+      - iot-network
+
+  # MQTT代理
+  mqtt:
+    image: eclipse-mosquitto:2
+    ports:
+      - "1883:1883"
+      - "9001:9001"  # WebSocket端口
+    volumes:
+      - ./config/mosquitto.conf:/mosquitto/config/mosquitto.conf
+      - mqtt_data:/mosquitto/data
+      - mqtt_logs:/mosquitto/log
+    networks:
+      - iot-network
+
+  # ChirpStack LoRaWAN网络服务器
+  chirpstack:
+    image: chirpstack/chirpstack:4
+    ports:
+      - "8080:8080"
+    environment:
+      - POSTGRESQL_DSN=postgres://postgres:postgres@postgres:5432/chirpstack?sslmode=disable
+      - REDIS_URL=redis://redis:6379
+    depends_on:
+      - postgres
+      - redis
+    networks:
+      - iot-network
+
+  # Grafana监控面板
+  grafana:
+    image: grafana/grafana:latest
+    ports:
+      - "3000:3000"
+    environment:
+      - GF_SECURITY_ADMIN_PASSWORD=admin
+    volumes:
+      - grafana_data:/var/lib/grafana
+      - ./config/grafana/dashboards:/etc/grafana/provisioning/dashboards
+      - ./config/grafana/datasources:/etc/grafana/provisioning/datasources
+    depends_on:
+      - influxdb
+    networks:
+      - iot-network
+
+  # Prometheus监控
+  prometheus:
+    image: prom/prometheus:latest
+    ports:
+      - "9090:9090"
+    volumes:
+      - ./config/prometheus.yml:/etc/prometheus/prometheus.yml
+      - prometheus_data:/prometheus
+    command:
+      - '--config.file=/etc/prometheus/prometheus.yml'
+      - '--storage.tsdb.path=/prometheus'
+      - '--web.console.libraries=/etc/prometheus/console_libraries'
+      - '--web.console.templates=/etc/prometheus/consoles'
+      - '--storage.tsdb.retention.time=200h'
+      - '--web.enable-lifecycle'
+    networks:
+      - iot-network
+
+  # 前端应用
+  frontend:
+    image: node:16-alpine
+    working_dir: /app
+    volumes:
+      - ./web:/app
+    ports:
+      - "3001:3000"
+    command: sh -c "npm install && npm start"
+    environment:
+      - REACT_APP_API_URL=http://localhost:8080
+    networks:
+      - iot-network
+
+volumes:
+  postgres_data:
+  influxdb_data:
+  redis_data:
+  mqtt_data:
+  mqtt_logs:
+  grafana_data:
+  prometheus_data:
+
+networks:
+  iot-network:
+    driver: bridge

+ 762 - 0
iot-base-station/docs/infrastructure-setup.md

@@ -0,0 +1,762 @@
+# 基础服务准备与配置指南
+
+## 概述
+
+本文档详细介绍了物联网基站管理系统所需的基础服务(PostgreSQL、InfluxDB、Redis、NATS、MQTT)的安装、配置和集成方法。特别针对已有Redis容器的情况提供了灵活的配置方案。
+
+## 服务架构
+
+```
+┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
+│   PostgreSQL    │    │    InfluxDB     │    │      Redis      │
+│   (元数据)      │    │   (时序数据)     │    │    (缓存)       │
+│                 │    │                 │    │                 │
+│ Port: 5432     │    │ Port: 8086     │    │ Port: 6379     │
+└─────────────────┘    └─────────────────┘    └─────────────────┘
+         │                       │                       │
+         └───────────────────────┼───────────────────────┘
+                                 │
+┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
+│      NATS      │    │      MQTT      │    │   IoT应用       │
+│   (消息队列)     │    │   (设备通信)     │    │                │
+│                 │    │                 │    │                 │
+│ Port: 4222     │    │ Port: 1883     │    │ Port: 8080     │
+└─────────────────┘    └─────────────────┘    └─────────────────┘
+```
+
+## 服务配置选项
+
+### 选项1:使用Docker Compose(推荐)
+
+完整启动所有服务(包括Redis):
+
+```bash
+# 启动所有服务
+docker-compose up -d
+
+# 查看服务状态
+docker-compose ps
+
+# 查看服务日志
+docker-compose logs -f
+```
+
+### 选项2:使用现有Redis + Docker Compose
+
+如果您已有Redis容器,可以修改Docker Compose配置:
+
+```bash
+# 启动除Redis外的服务
+docker-compose up -d postgres influxdb nats mqtt
+
+# 或者使用自定义配置文件
+docker-compose -f docker-compose-without-redis.yml up -d
+```
+
+### 选项3:混合部署(本地服务 + Docker)
+
+结合本地已有服务和Docker容器:
+
+```bash
+# 仅启动Docker中的服务
+docker-compose up -d postgres influxdb nats mqtt
+
+# 使用本地Redis(确保已运行)
+# 无需额外操作,应用会自动连接到本地Redis
+```
+
+## 各服务详细配置
+
+### 1. PostgreSQL(元数据存储)
+
+#### Docker部署
+
+```yaml
+# docker-compose.yml 中的PostgreSQL配置
+postgres:
+  image: postgres:14
+  environment:
+    - POSTGRES_USER=postgres
+    - POSTGRES_PASSWORD=postgres
+    - POSTGRES_DB=iot_base_station
+  ports:
+    - "5432:5432"
+  volumes:
+    - postgres_data:/var/lib/postgresql/data
+    - ./scripts/init-postgres.sql:/docker-entrypoint-initdb.d/init-postgres.sql
+```
+
+#### 本地安装
+
+```bash
+# Ubuntu/Debian
+sudo apt update
+sudo apt install postgresql postgresql-contrib
+
+# CentOS/RHEL
+sudo yum install postgresql-server postgresql-contrib
+sudo postgresql-setup initdb
+sudo systemctl start postgresql
+sudo systemctl enable postgresql
+
+# macOS (使用Homebrew)
+brew install postgresql
+brew services start postgresql
+```
+
+#### 配置数据库
+
+```bash
+# 创建数据库和用户
+sudo -u postgres psql
+CREATE USER iot_user WITH PASSWORD 'iot_password';
+CREATE DATABASE iot_base_station OWNER iot_user;
+GRANT ALL PRIVILEGES ON DATABASE iot_base_station TO iot_user;
+\q
+
+# 运行迁移
+go run cmd/migrate/main.go up
+```
+
+#### 连接测试
+
+```bash
+# 使用psql连接
+psql -h localhost -U postgres -d iot_base_station
+
+# 或使用Docker
+docker-compose exec postgres psql -U postgres -d iot_base_station
+```
+
+### 2. InfluxDB(时序数据存储)
+
+#### Docker部署
+
+```yaml
+# docker-compose.yml 中的InfluxDB配置
+influxdb:
+  image: influxdb:2.0
+  environment:
+    - DOCKER_INFLUXDB_INIT_MODE=setup
+    - DOCKER_INFLUXDB_INIT_USERNAME=admin
+    - DOCKER_INFLUXDB_INIT_PASSWORD=adminpassword
+    - DOCKER_INFLUXDB_INIT_ORG=iot-org
+    - DOCKER_INFLUXDB_INIT_BUCKET=iot-data
+    - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=influxdb-token
+  ports:
+    - "8086:8086"
+  volumes:
+    - influxdb_data:/var/lib/influxdb2
+```
+
+#### 本地安装
+
+```bash
+# 下载InfluxDB 2.0
+wget https://dl.influxdata.com/influxdb/releases/influxdb2-2.0.7-linux-amd64.tar.gz
+tar xvfz influxdb2-2.0.7-linux-amd64.tar.gz
+sudo cp influxdb2-2.0.7-linux-amd64/influxd /usr/local/bin/
+
+# 创建配置目录
+sudo mkdir -p /etc/influxdb2
+sudo chown $USER:$USER /etc/influxdb2
+
+# 启动InfluxDB
+influxd --config-path /etc/influxdb2
+```
+
+#### 初始化配置
+
+```bash
+# 访问Web UI进行初始化
+open http://localhost:8086
+
+# 或使用CLI初始化
+influx setup \
+  --username admin \
+  --password adminpassword \
+  --org iot-org \
+  --bucket iot-data \
+  --retention 30d \
+  --force
+```
+
+#### 连接测试
+
+```bash
+# 检查健康状态
+curl -s http://localhost:8086/health
+
+# 使用CLI查询
+influx query 'from(bucket:"iot-data") |> range(start:-1h)'
+```
+
+### 3. Redis(缓存)
+
+#### 使用现有Redis容器
+
+如果您已有Redis容器,只需确保以下配置:
+
+1. **端口映射**:确保Redis端口映射到主机
+   ```bash
+   # 检查现有Redis容器端口映射
+   docker ps | grep redis
+   # 如果没有端口映射,重新启动容器
+   docker stop redis-container
+   docker run -d --name redis-container -p 6379:6379 redis:6-alpine
+   ```
+
+2. **网络连接**:确保应用可以连接到Redis
+   ```bash
+   # 测试连接
+   docker-compose exec app ping redis-container
+   # 或使用主机网络
+   docker run --network host redis-cli ping
+   ```
+
+3. **配置文件更新**:修改应用配置以使用现有Redis
+   ```yaml
+   # config/config.dev.yaml
+   redis:
+     host: "localhost"  # 或 "host.docker.internal" 如果在Docker中
+     port: "6379"
+     password: ""  # 如果有密码,请填写
+     db: 0
+   ```
+
+#### Docker部署(如果需要)
+
+```yaml
+# docker-compose.yml 中的Redis配置
+redis:
+  image: redis:6-alpine
+  ports:
+    - "6379:6379"
+  volumes:
+    - redis_data:/data
+  command: redis-server --appendonly yes
+```
+
+#### 本地安装
+
+```bash
+# Ubuntu/Debian
+sudo apt update
+sudo apt install redis-server
+
+# CentOS/RHEL
+sudo yum install redis
+sudo systemctl start redis
+sudo systemctl enable redis
+
+# macOS (使用Homebrew)
+brew install redis
+brew services start redis
+```
+
+#### 配置优化
+
+```bash
+# 编辑Redis配置文件
+sudo nano /etc/redis/redis.conf
+
+# 推荐配置
+maxmemory 256mb
+maxmemory-policy allkeys-lru
+save 900 1
+save 300 10
+save 60 10000
+
+# 重启Redis
+sudo systemctl restart redis
+```
+
+#### 连接测试
+
+```bash
+# 使用redis-cli
+redis-cli ping
+
+# 或使用Docker
+docker-compose exec redis redis-cli ping
+
+# 测试读写
+redis-cli set test_key "test_value"
+redis-cli get test_key
+```
+
+### 4. NATS(消息队列)
+
+#### Docker部署
+
+```yaml
+# docker-compose.yml 中的NATS配置
+nats:
+  image: nats:2-alpine
+  ports:
+    - "4222:4222"
+    - "8222:8222"  # HTTP监控端口
+  command: ["-js", "-m", "8222"]  # 启用JetStream和监控
+```
+
+#### 本地安装
+
+```bash
+# 下载NATS Server
+wget https://github.com/nats-io/nats-server/releases/download/v2.9.1/nats-server-v2.9.1-linux-amd64.tar.gz
+tar xvfz nats-server-v2.9.1-linux-amd64.tar.gz
+sudo cp nats-server-v2.9.1-linux-amd64/nats-server /usr/local/bin/
+
+# 启动NATS
+nats-server -js -m 8222
+```
+
+#### 配置文件
+
+```bash
+# 创建NATS配置文件
+mkdir -p ~/.config/nats
+cat > ~/.config/nats/nats.conf << EOF
+server_name: "nats-iot"
+jetstream: {
+  store_dir: "/tmp/nats-jetstream"
+  max_memory_store: 1GB
+  max_file_store: 10GB
+}
+
+http_port: 8222
+EOF
+
+# 使用配置文件启动
+nats-server -c ~/.config/nats/nats.conf
+```
+
+#### 连接测试
+
+```bash
+# 检查NATS状态
+curl -s http://localhost:8222/varz | jq
+
+# 使用nats-cli测试
+nats sub "test.subject" &
+nats pub "test.subject" "Hello, NATS!"
+```
+
+### 5. MQTT(设备通信)
+
+#### Docker部署
+
+```yaml
+# docker-compose.yml 中的MQTT配置
+mqtt:
+  image: eclipse-mosquitto:2
+  ports:
+    - "1883:1883"
+    - "9001:9001"  # WebSocket端口
+  volumes:
+    - ./config/mosquitto.conf:/mosquitto/config/mosquitto.conf
+    - mqtt_data:/mosquitto/data
+    - mqtt_logs:/mosquitto/log
+```
+
+#### Mosquitto配置
+
+```bash
+# 创建Mosquitto配置文件
+mkdir -p config
+cat > config/mosquitto.conf << EOF
+# 基本配置
+persistence true
+persistence_location /mosquitto/data/
+log_dest file /mosquitto/log/mosquitto.log
+log_type error
+log_type warning
+log_type notice
+log_type information
+
+# 网络配置
+listener 1883
+protocol mqtt
+
+# WebSocket支持
+listener 9001
+protocol websockets
+
+# 认证(可选)
+# allow_anonymous false
+# password_file /mosquitto/config/passwd
+EOF
+```
+
+#### 本地安装
+
+```bash
+# Ubuntu/Debian
+sudo apt update
+sudo apt install mosquitto mosquitto-clients
+
+# CentOS/RHEL
+sudo yum install mosquitto
+sudo systemctl start mosquitto
+sudo systemctl enable mosquitto
+
+# macOS (使用Homebrew)
+brew install mosquitto
+brew services start mosquitto
+```
+
+#### 连接测试
+
+```bash
+# 订阅主题
+mosquitto_sub -h localhost -t "iot/data/+/+"
+
+# 发布消息
+mosquitto_pub -h localhost -t "iot/data/test/temperature" -m '{"temperature": 25.5}'
+
+# 或使用Docker
+docker-compose exec mqtt mosquitto_sub -h localhost -t "iot/data/+/+"
+docker-compose exec mqtt mosquitto_pub -h localhost -t "iot/data/test/temperature" -m '{"temperature": 25.5}'
+```
+
+## 服务集成配置
+
+### 1. 应用配置文件
+
+创建适合您环境的配置文件:
+
+```bash
+# 复制基础配置
+cp config/config.yaml config/config.local.yaml
+```
+
+编辑 `config/config.local.yaml`:
+
+```yaml
+server:
+  port: "8080"
+  mode: "debug"
+
+database:
+  postgres:
+    host: "localhost"  # 或 "host.docker.internal"
+    port: "5432"
+    user: "postgres"
+    password: "postgres"
+    dbname: "iot_base_station"
+  
+  influxdb:
+    url: "http://localhost:8086"
+    token: "influxdb-token"
+    org: "iot-org"
+    bucket: "iot-data"
+
+redis:
+  host: "localhost"  # 或 "host.docker.internal"
+  port: "6379"
+  password: ""  # 如果有密码,请填写
+  db: 0
+
+nats:
+  url: "nats://localhost:4222"
+
+mqtt:
+  broker: "tcp://localhost:1883"
+  client_id: "iot-gateway-dev"
+```
+
+### 2. 环境变量
+
+创建 `.env` 文件:
+
+```bash
+# .env
+CONFIG_PATH=config/config.local.yaml
+GIN_MODE=debug
+
+# 如果使用Docker中的服务
+POSTGRES_HOST=postgres
+INFLUXDB_URL=http://influxdb:8086
+REDIS_HOST=redis
+NATS_URL=nats://nats:4222
+MQTT_BROKER=tcp://mqtt:1883
+```
+
+### 3. Docker Compose自定义配置
+
+如果您已有Redis容器,可以创建自定义的Docker Compose文件:
+
+```yaml
+# docker-compose-without-redis.yml
+version: '3.8'
+
+services:
+  app:
+    build: .
+    ports:
+      - "8080:8080"
+    environment:
+      - DB_HOST=postgres
+      - DB_PORT=5432
+      - DB_USER=postgres
+      - DB_PASSWORD=postgres
+      - DB_NAME=iot_base_station
+      - INFLUXDB_URL=http://influxdb:8086
+      - INFLUXDB_TOKEN=influxdb-token
+      - INFLUXDB_ORG=iot-org
+      - INFLUXDB_BUCKET=iot-data
+      - REDIS_HOST=host.docker.internal  # 使用主机上的Redis
+      - REDIS_PORT=6379
+      - NATS_URL=nats://nats:4222
+      - MQTT_BROKER=tcp://mqtt:1883
+    depends_on:
+      - postgres
+      - influxdb
+      - nats
+      - mqtt
+    volumes:
+      - ./logs:/app/logs
+      - ./uploads:/app/uploads
+    networks:
+      - iot-network
+    extra_hosts:
+      - "host.docker.internal:host-gateway"  # 允许访问主机服务
+
+  postgres:
+    image: postgres:14
+    environment:
+      - POSTGRES_USER=postgres
+      - POSTGRES_PASSWORD=postgres
+      - POSTGRES_DB=iot_base_station
+    ports:
+      - "5432:5432"
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+    networks:
+      - iot-network
+
+  influxdb:
+    image: influxdb:2.0
+    environment:
+      - DOCKER_INFLUXDB_INIT_MODE=setup
+      - DOCKER_INFLUXDB_INIT_USERNAME=admin
+      - DOCKER_INFLUXDB_INIT_PASSWORD=adminpassword
+      - DOCKER_INFLUXDB_INIT_ORG=iot-org
+      - DOCKER_INFLUXDB_INIT_BUCKET=iot-data
+      - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=influxdb-token
+    ports:
+      - "8086:8086"
+    volumes:
+      - influxdb_data:/var/lib/influxdb2
+    networks:
+      - iot-network
+
+  nats:
+    image: nats:2-alpine
+    ports:
+      - "4222:4222"
+      - "8222:8222"
+    command: ["-js", "-m", "8222"]
+    networks:
+      - iot-network
+
+  mqtt:
+    image: eclipse-mosquitto:2
+    ports:
+      - "1883:1883"
+      - "9001:9001"
+    volumes:
+      - ./config/mosquitto.conf:/mosquitto/config/mosquitto.conf
+      - mqtt_data:/mosquitto/data
+      - mqtt_logs:/mosquitto/log
+    networks:
+      - iot-network
+
+volumes:
+  postgres_data:
+  influxdb_data:
+  mqtt_data:
+  mqtt_logs:
+
+networks:
+  iot-network:
+    driver: bridge
+```
+
+## 服务启动脚本
+
+### 1. 完整启动脚本
+
+```bash
+#!/bin/bash
+# scripts/start-infrastructure.sh
+
+set -e
+
+echo "=== 启动物联网基站基础服务 ==="
+
+# 检查Docker是否运行
+if ! docker info > /dev/null 2>&1; then
+    echo "错误: Docker未运行,请先启动Docker"
+    exit 1
+fi
+
+# 检查Redis是否已运行
+if docker ps --format "table {{.Names}}" | grep -q "redis"; then
+    echo "✓ 检测到Redis容器已运行"
+    echo "启动除Redis外的服务..."
+    docker-compose -f docker-compose-without-redis.yml up -d
+else
+    echo "Redis容器未运行,启动所有服务..."
+    docker-compose up -d
+fi
+
+# 等待服务启动
+echo "等待服务启动..."
+sleep 10
+
+# 检查服务状态
+echo "检查服务状态..."
+docker-compose ps
+
+# 初始化数据库
+echo "初始化数据库..."
+docker-compose exec -T postgres psql -U postgres -c "CREATE DATABASE iot_base_station;" || echo "数据库可能已存在"
+
+# 运行迁移
+echo "运行数据库迁移..."
+go run cmd/migrate/main.go up
+
+echo "=== 基础服务启动完成 ==="
+echo "PostgreSQL: localhost:5432"
+echo "InfluxDB: http://localhost:8086"
+echo "Redis: localhost:6379"
+echo "NATS: localhost:4222"
+echo "MQTT: localhost:1883"
+```
+
+### 2. 服务健康检查脚本
+
+```bash
+#!/bin/bash
+# scripts/health-check.sh
+
+echo "=== 服务健康检查 ==="
+
+# 检查PostgreSQL
+if docker-compose exec -T postgres pg_isready -U postgres > /dev/null 2>&1; then
+    echo "✓ PostgreSQL: 健康"
+else
+    echo "✗ PostgreSQL: 不可用"
+fi
+
+# 检查InfluxDB
+if curl -s http://localhost:8086/health > /dev/null 2>&1; then
+    echo "✓ InfluxDB: 健康"
+else
+    echo "✗ InfluxDB: 不可用"
+fi
+
+# 检查Redis
+if docker-compose exec -T redis redis-cli ping > /dev/null 2>&1; then
+    echo "✓ Redis: 健康"
+else
+    echo "✗ Redis: 不可用"
+fi
+
+# 检查NATS
+if curl -s http://localhost:8222/varz > /dev/null 2>&1; then
+    echo "✓ NATS: 健康"
+else
+    echo "✗ NATS: 不可用"
+fi
+
+# 检查MQTT
+if docker-compose exec -T mqtt mosquitto_pub -h localhost -t '$SYS/broker/version' -m 'test' > /dev/null 2>&1; then
+    echo "✓ MQTT: 健康"
+else
+    echo "✗ MQTT: 不可用"
+fi
+
+echo "=== 健康检查完成 ==="
+```
+
+## 故障排除
+
+### 1. 端口冲突
+
+```bash
+# 查找占用端口的进程
+lsof -i :5432  # PostgreSQL
+lsof -i :8086  # InfluxDB
+lsof -i :6379  # Redis
+lsof -i :4222  # NATS
+lsof -i :1883  # MQTT
+
+# 停止占用端口的进程
+kill -9 <PID>
+```
+
+### 2. 网络连接问题
+
+```bash
+# 检查Docker网络
+docker network ls
+docker network inspect iot-base-station_iot-network
+
+# 测试容器间连接
+docker-compose exec app ping postgres
+docker-compose exec app ping redis
+```
+
+### 3. 数据持久化问题
+
+```bash
+# 检查Docker卷
+docker volume ls
+docker volume inspect iot-base-station_postgres_data
+
+# 备份数据
+docker-compose exec postgres pg_dump -U postgres iot_base_station > backup.sql
+```
+
+### 4. 性能优化
+
+```bash
+# 监控资源使用
+docker stats
+
+# 调整容器资源限制
+# 在docker-compose.yml中添加
+services:
+  postgres:
+    deploy:
+      resources:
+        limits:
+          cpus: '1.0'
+          memory: 1G
+```
+
+## 生产环境注意事项
+
+1. **安全性**:
+   - 更改默认密码
+   - 启用TLS/SSL
+   - 配置防火墙规则
+
+2. **备份策略**:
+   - 定期备份PostgreSQL数据库
+   - 备份InfluxDB数据
+   - 备份配置文件
+
+3. **监控**:
+   - 设置服务健康检查
+   - 配置告警通知
+   - 监控资源使用情况
+
+4. **高可用性**:
+   - 配置主从复制
+   - 设置负载均衡
+   - 实现故障转移
+
+通过以上配置,您可以根据自己的环境需求灵活部署物联网基站管理系统的基础服务。

+ 549 - 0
iot-base-station/docs/local-development.md

@@ -0,0 +1,549 @@
+# 本地开发调试指南
+
+## 概述
+
+本文档提供了物联网基站管理系统的本地开发环境搭建和调试步骤,帮助开发者快速搭建开发环境并进行本地调试。
+
+## 环境要求
+
+### 基础环境
+- **Go**: 1.19 或更高版本
+- **Docker**: 20.10 或更高版本
+- **Docker Compose**: 2.0 或更高版本
+- **Git**: 最新版本
+
+### 开发工具(推荐)
+- **IDE**: VS Code / GoLand
+- **数据库工具**: DBeaver / pgAdmin
+- **API测试**: Postman / Insomnia
+- **MQTT客户端**: MQTT Explorer / mosquitto_pub/sub
+
+## 环境搭建
+
+### 1. 克隆项目
+
+```bash
+git clone https://github.com/your-username/iot-base-station.git
+cd iot-base-station
+```
+
+### 2. 安装Go依赖
+
+```bash
+go mod download
+go mod tidy
+```
+
+### 3. 启动基础服务
+
+使用Docker Compose启动数据库、缓存等基础服务:
+
+```bash
+# 启动基础服务(不包括应用)
+docker-compose up -d postgres influxdb redis nats mqtt
+
+# 查看服务状态
+docker-compose ps
+```
+
+### 4. 等待服务就绪
+
+等待所有服务启动完成,可以通过以下命令检查:
+
+```bash
+# 检查PostgreSQL
+docker-compose logs postgres | grep "database system is ready"
+
+# 检查InfluxDB
+curl -s http://localhost:8086/health
+
+# 检查Redis
+docker-compose exec redis redis-cli ping
+
+# 检查NATS
+curl -s http://localhost:8222/varz
+
+# 检查MQTT
+docker-compose exec mqtt mosquitto_sub -h localhost -t '$SYS/#' -C 1
+```
+
+## 本地开发配置
+
+### 1. 创建开发配置文件
+
+创建一个开发专用的配置文件:
+
+```bash
+cp config/config.yaml config/config.dev.yaml
+```
+
+编辑 `config/config.dev.yaml`,修改以下配置:
+
+```yaml
+server:
+  port: "8080"
+  mode: "debug"  # 开发模式
+
+database:
+  postgres:
+    host: "localhost"
+    port: "5432"
+    user: "postgres"
+    password: "postgres"
+    dbname: "iot_base_station"
+  
+  influxdb:
+    url: "http://localhost:8086"
+    token: "dev-token"
+    org: "iot-org"
+    bucket: "iot-data"
+
+redis:
+  host: "localhost"
+  port: "6379"
+
+nats:
+  url: "nats://localhost:4222"
+
+mqtt:
+  broker: "tcp://localhost:1883"
+  client_id: "iot-gateway-dev"
+
+logging:
+  level: "debug"
+  output: "stdout"  # 输出到控制台
+```
+
+### 2. 初始化数据库
+
+创建数据库初始化脚本:
+
+```bash
+# 创建PostgreSQL数据库
+docker-compose exec postgres psql -U postgres -c "CREATE DATABASE iot_base_station;"
+
+# 运行数据库迁移
+go run cmd/migrate/main.go up
+```
+
+### 3. 配置环境变量
+
+创建 `.env` 文件:
+
+```bash
+# .env
+CONFIG_PATH=config/config.dev.yaml
+GIN_MODE=debug
+```
+
+## 本地运行
+
+### 1. 运行主服务器
+
+```bash
+# 方式1:直接运行
+go run cmd/server/main.go
+
+# 方式2:使用环境变量
+CONFIG_PATH=config/config.dev.yaml go run cmd/server/main.go
+
+# 方式3:使用Air热重载(推荐)
+air -c .air.toml
+```
+
+### 2. 运行数据网关
+
+```bash
+# 新终端窗口
+go run cmd/gateway/main.go
+```
+
+### 3. 运行监控服务
+
+```bash
+# 新终端窗口
+go run cmd/monitor/main.go
+```
+
+### 4. 运行设备模拟器
+
+```bash
+# 新终端窗口
+go run simulations/main.go -broker=tcp://localhost:1883 -count=5 -interval=30s
+```
+
+## 调试技巧
+
+### 1. 使用Delve调试器
+
+安装Delve调试器:
+
+```bash
+go install github.com/go-delve/delve/cmd/dlv@latest
+```
+
+启动调试会话:
+
+```bash
+# 调试主服务器
+dlv debug cmd/server/main.go
+
+# 调试特定函数
+dlv debug --headless --listen=:2345 --api-version=2 cmd/server/main.go
+```
+
+在VS Code中配置调试:
+
+```json
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Launch Server",
+      "type": "go",
+      "request": "launch",
+      "mode": "debug",
+      "program": "${workspaceFolder}/cmd/server/main.go",
+      "env": {
+        "CONFIG_PATH": "config/config.dev.yaml"
+      }
+    },
+    {
+      "name": "Launch Gateway",
+      "type": "go",
+      "request": "launch",
+      "mode": "debug",
+      "program": "${workspaceFolder}/cmd/gateway/main.go",
+      "env": {
+        "CONFIG_PATH": "config/config.dev.yaml"
+      }
+    }
+  ]
+}
+```
+
+### 2. 日志调试
+
+在代码中添加调试日志:
+
+```go
+import "go.uber.org/zap"
+
+// 在函数中添加调试日志
+logger.Debug("Processing device data", 
+    zap.String("device_id", deviceID),
+    zap.Any("data", data))
+```
+
+### 3. 性能分析
+
+启用性能分析:
+
+```go
+import (
+    _ "net/http/pprof"
+    "net/http"
+)
+
+// 在main函数中添加
+go func() {
+    log.Println(http.ListenAndServe("localhost:6060", nil))
+}()
+```
+
+访问性能分析页面:
+- CPU分析: http://localhost:6060/debug/pprof/profile
+- 内存分析: http://localhost:6060/debug/pprof/heap
+- Goroutine分析: http://localhost:6060/debug/pprof/goroutine
+
+### 4. 数据库调试
+
+使用DBeaver连接PostgreSQL:
+- 主机: localhost
+- 端口: 5432
+- 数据库: iot_base_station
+- 用户名: postgres
+- 密码: postgres
+
+使用InfluxDB Web UI:
+- 访问: http://localhost:8086
+- 使用初始化时设置的组织和令牌
+
+## 测试
+
+### 1. 运行单元测试
+
+```bash
+# 运行所有测试
+go test ./...
+
+# 运行特定包的测试
+go test ./internal/device
+
+# 运行测试并生成覆盖率报告
+go test -coverprofile=coverage.out ./...
+go tool cover -html=coverage.out
+```
+
+### 2. 运行集成测试
+
+```bash
+# 运行集成测试
+go test -tags=integration ./tests/integration/...
+
+# 运行端到端测试
+go test -tags=e2e ./tests/e2e/...
+```
+
+### 3. API测试
+
+使用Postman导入API集合:
+1. 打开Postman
+2. 导入 `docs/postman_collection.json`
+3. 设置环境变量:
+   - `base_url`: http://localhost:8080
+   - `token`: 从登录API获取
+
+使用curl测试:
+
+```bash
+# 注册设备
+curl -X POST http://localhost:8080/api/v1/devices \
+  -H "Content-Type: application/json" \
+  -d '{
+    "name": "测试温度传感器",
+    "type": "temperature_sensor",
+    "protocol": "mqtt",
+    "metadata": {
+      "location": "机房A"
+    }
+  }'
+
+# 获取设备列表
+curl -X GET http://localhost:8080/api/v1/devices
+
+# 获取实时数据
+curl -X GET "http://localhost:8080/api/v1/data/realtime?device_id=temp_sensor_01"
+```
+
+## 常见问题
+
+### 1. 端口冲突
+
+如果遇到端口冲突,可以修改配置文件中的端口设置:
+
+```yaml
+server:
+  port: "8081"  # 修改为其他端口
+```
+
+或者停止占用端口的进程:
+
+```bash
+# 查找占用端口的进程
+lsof -i :8080
+
+# 停止进程
+kill -9 <PID>
+```
+
+### 2. 数据库连接失败
+
+检查数据库服务状态:
+
+```bash
+docker-compose logs postgres
+```
+
+确保数据库配置正确:
+
+```yaml
+database:
+  postgres:
+    host: "localhost"  # 如果使用Docker,可能需要改为host.docker.internal
+```
+
+### 3. MQTT连接失败
+
+检查MQTT服务状态:
+
+```bash
+docker-compose logs mqtt
+```
+
+使用MQTT客户端测试连接:
+
+```bash
+# 订阅主题
+docker-compose exec mqtt mosquitto_sub -h localhost -t "iot/data/+/+"
+
+# 发布消息
+docker-compose exec mqtt mosquitto_pub -h localhost -t "iot/data/test/temperature" -m '{"temperature": 25.5}'
+```
+
+### 4. 依赖问题
+
+如果遇到依赖问题,尝试重新安装:
+
+```bash
+# 清理模块缓存
+go clean -modcache
+
+# 重新下载依赖
+go mod download
+
+# 整理依赖
+go mod tidy
+```
+
+## 开发工具
+
+### 1. 热重载
+
+安装Air热重载工具:
+
+```bash
+go install github.com/cosmtrek/air@latest
+```
+
+创建 `.air.toml` 配置文件:
+
+```toml
+root = "."
+testdata_dir = "testdata"
+tmp_dir = "tmp"
+
+[build]
+  args_bin = []
+  bin = "./tmp/main"
+  cmd = "go build -o ./tmp/main ./cmd/server"
+  delay = 1000
+  exclude_dir = ["assets", "tmp", "vendor", "testdata"]
+  exclude_file = []
+  exclude_regex = ["_test.go"]
+  exclude_unchanged = false
+  follow_symlink = false
+  full_bin = ""
+  include_dir = []
+  include_ext = ["go", "tpl", "tmpl", "html"]
+  kill_delay = "0s"
+  log = "build-errors.log"
+  send_interrupt = false
+  stop_on_root = false
+
+[color]
+  app = ""
+  build = "yellow"
+  main = "magenta"
+  runner = "green"
+  watcher = "cyan"
+
+[log]
+  time = false
+
+[misc]
+  clean_on_exit = false
+```
+
+### 2. 代码格式化
+
+安装gofmt和golint:
+
+```bash
+go install golang.org/x/tools/cmd/goimports@latest
+go install golang.org/x/lint/golint@latest
+```
+
+配置VS Code自动格式化:
+
+```json
+{
+  "go.useLanguageServer": true,
+  "go.formatTool": "goimports",
+  "go.lintTool": "golint",
+  "go.lintOnSave": "package",
+  "editor.formatOnSave": true,
+  "editor.codeActionsOnSave": {
+    "source.organizeImports": true
+  }
+}
+```
+
+### 3. Git钩子
+
+安装pre-commit钩子:
+
+```bash
+# 安装pre-commit
+pip install pre-commit
+
+# 创建.pre-commit-config.yaml
+pre-commit install
+```
+
+`.pre-commit-config.yaml` 内容:
+
+```yaml
+repos:
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.4.0
+    hooks:
+      - id: trailing-whitespace
+      - id: end-of-file-fixer
+      - id: check-yaml
+      - id: check-added-large-files
+
+  - repo: https://github.com/tekwizely/pre-commit-golang
+    rev: v1.0.0-rc.1
+    hooks:
+      - id: go-fmt
+      - id: go-vet-mod
+      - id: go-mod-tidy
+```
+
+## 性能优化
+
+### 1. 数据库优化
+
+- 添加适当的索引
+- 使用连接池
+- 优化查询语句
+
+### 2. 内存优化
+
+- 使用对象池
+- 避免内存泄漏
+- 监控内存使用
+
+### 3. 并发优化
+
+- 使用goroutine池
+- 避免竞态条件
+- 使用channel进行通信
+
+## 部署准备
+
+### 1. 构建生产版本
+
+```bash
+# 构建二进制文件
+CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o bin/server cmd/server/main.go
+CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o bin/gateway cmd/gateway/main.go
+CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o bin/monitor cmd/monitor/main.go
+```
+
+### 2. 创建Docker镜像
+
+```bash
+# 构建镜像
+docker build -t iot-base-station:latest .
+
+# 推送到镜像仓库
+docker push your-registry/iot-base-station:latest
+```
+
+### 3. 配置生产环境
+
+创建生产环境配置文件 `config/config.prod.yaml`,设置生产环境参数。
+
+通过以上步骤,您应该能够成功搭建物联网基站管理系统的本地开发环境,并进行有效的调试和开发工作。

+ 28 - 0
iot-base-station/go.mod

@@ -0,0 +1,28 @@
+module iot-base-station
+
+go 1.19
+
+require (
+	github.com/gin-gonic/gin v1.9.0
+	github.com/eclipse/paho.mqtt.golang v1.4.3
+	github.com/plgd-dev/go-coap/v2 v2.3.0
+	github.com/influxdata/influxdb-client-go/v2 v2.12.3
+	github.com/lib/pq v1.10.9
+	github.com/go-redis/redis/v8 v8.11.5
+	github.com/nats-io/nats.go v1.28.0
+	github.com/prometheus/client_golang v1.16.0
+	github.com/gorilla/websocket v1.5.0
+	github.com/spf13/viper v1.15.0
+	github.com/golang-jwt/jwt/v5 v5.0.0
+	go.uber.org/zap v1.24.0
+	github.com/stretchr/testify v1.8.4
+	github.com/swaggo/gin-swagger v1.6.0
+	github.com/swaggo/files v1.0.1
+	github.com/swaggo/swag v1.16.1
+	github.com/robfig/cron/v3 v3.0.1
+	github.com/google/uuid v1.3.0
+	gopkg.in/yaml.v3 v3.0.1
+	github.com/golang-migrate/migrate/v4 v4.15.2
+	gorm.io/gorm v1.25.2
+	gorm.io/driver/postgres v1.5.2
+)

+ 187 - 0
iot-base-station/internal/device/device.go

@@ -0,0 +1,187 @@
+package device
+
+import (
+	"time"
+)
+
+// Device 设备模型
+type Device struct {
+	ID          string            `json:"id" gorm:"primaryKey"`
+	Name        string            `json:"name" gorm:"not null"`
+	Type        string            `json:"type" gorm:"not null"`
+	Protocol    string            `json:"protocol" gorm:"not null"`
+	Status      DeviceStatus      `json:"status" gorm:"default:'offline'"`
+	LastSeen    *time.Time        `json:"last_seen"`
+	Metadata    map[string]string `json:"metadata" gorm:"serializer:json"`
+	Config      DeviceConfig      `json:"config" gorm:"serializer:json"`
+	Firmware    FirmwareInfo      `json:"firmware" gorm:"serializer:json"`
+	Location    LocationInfo      `json:"location" gorm:"serializer:json"`
+	CreatedAt   time.Time         `json:"created_at"`
+	UpdatedAt   time.Time         `json:"updated_at"`
+	DeletedAt   *time.Time        `json:"-" gorm:"index"`
+}
+
+// DeviceStatus 设备状态
+type DeviceStatus string
+
+const (
+	StatusOnline   DeviceStatus = "online"
+	StatusOffline  DeviceStatus = "offline"
+	StatusError    DeviceStatus = "error"
+	StatusUpdating DeviceStatus = "updating"
+)
+
+// DeviceConfig 设备配置
+type DeviceConfig struct {
+	ReportInterval int                    `json:"report_interval"` // 报告间隔(秒)
+	Threshold      map[string]interface{} `json:"threshold"`      // 阈值设置
+	Enabled        bool                   `json:"enabled"`        // 是否启用
+	Custom         map[string]interface{} `json:"custom"`         // 自定义配置
+}
+
+// FirmwareInfo 固件信息
+type FirmwareInfo struct {
+	Version     string    `json:"version"`
+	Checksum    string    `json:"checksum"`
+	ReleaseDate time.Time `json:"release_date"`
+	Description string    `json:"description"`
+	URL         string    `json:"url"`
+}
+
+// LocationInfo 位置信息
+type LocationInfo struct {
+	Latitude  float64 `json:"latitude"`
+	Longitude float64 `json:"longitude"`
+	Altitude  float64 `json:"altitude"`
+	Address   string  `json:"address"`
+	Building  string  `json:"building"`
+	Floor     string  `json:"floor"`
+	Room      string  `json:"room"`
+}
+
+// DeviceData 设备数据
+type DeviceData struct {
+	DeviceID    string                 `json:"device_id"`
+	Timestamp   time.Time              `json:"timestamp"`
+	Metrics     map[string]interface{} `json:"metrics"`
+	Location    *LocationInfo          `json:"location,omitempty"`
+	Quality     DataQuality            `json:"quality"`
+}
+
+// DataQuality 数据质量
+type DataQuality struct {
+	Good    bool    `json:"good"`
+	Accuracy float64 `json:"accuracy"`
+	Source  string  `json:"source"`
+}
+
+// DeviceEvent 设备事件
+type DeviceEvent struct {
+	ID        string                 `json:"id"`
+	DeviceID  string                 `json:"device_id"`
+	Type      EventType              `json:"type"`
+	Severity  EventSeverity          `json:"severity"`
+	Message   string                 `json:"message"`
+	Data      map[string]interface{} `json:"data,omitempty"`
+	Timestamp time.Time              `json:"timestamp"`
+	Acked     bool                   `json:"acked"`
+	AckedBy   string                 `json:"acked_by,omitempty"`
+	AckedAt   *time.Time             `json:"acked_at,omitempty"`
+}
+
+// EventType 事件类型
+type EventType string
+
+const (
+	EventConnect     EventType = "connect"
+	EventDisconnect  EventType = "disconnect"
+	EventError       EventType = "error"
+	EventMaintenance EventType = "maintenance"
+	EventFirmware    EventType = "firmware"
+	EventConfig      EventType = "config"
+	EventAlert       EventType = "alert"
+)
+
+// EventSeverity 事件严重程度
+type EventSeverity string
+
+const (
+	SeverityInfo    EventSeverity = "info"
+	SeverityWarning EventSeverity = "warning"
+	SeverityError   EventSeverity = "error"
+	SeverityCritical EventSeverity = "critical"
+)
+
+// CreateDeviceRequest 创建设备请求
+type CreateDeviceRequest struct {
+	Name     string            `json:"name" binding:"required"`
+	Type     string            `json:"type" binding:"required"`
+	Protocol string            `json:"protocol" binding:"required"`
+	Metadata map[string]string `json:"metadata"`
+	Config   DeviceConfig      `json:"config"`
+	Location LocationInfo      `json:"location"`
+}
+
+// UpdateDeviceRequest 更新设备请求
+type UpdateDeviceRequest struct {
+	Name     string            `json:"name"`
+	Metadata map[string]string `json:"metadata"`
+	Config   DeviceConfig      `json:"config"`
+	Location LocationInfo      `json:"location"`
+}
+
+// UpdateDeviceConfigRequest 更新设备配置请求
+type UpdateDeviceConfigRequest struct {
+	Config DeviceConfig `json:"config" binding:"required"`
+}
+
+// UpdateFirmwareRequest 更新固件请求
+type UpdateFirmwareRequest struct {
+	Version     string `json:"version" binding:"required"`
+	URL         string `json:"url" binding:"required"`
+	Description string `json:"description"`
+}
+
+// DeviceResponse 设备响应
+type DeviceResponse struct {
+	ID          string            `json:"id"`
+	Name        string            `json:"name"`
+	Type        string            `json:"type"`
+	Protocol    string            `json:"protocol"`
+	Status      DeviceStatus      `json:"status"`
+	LastSeen    *time.Time        `json:"last_seen"`
+	Metadata    map[string]string `json:"metadata"`
+	Config      DeviceConfig      `json:"config"`
+	Firmware    FirmwareInfo      `json:"firmware"`
+	Location    LocationInfo      `json:"location"`
+	CreatedAt   time.Time         `json:"created_at"`
+	UpdatedAt   time.Time         `json:"updated_at"`
+}
+
+// ToResponse 转换为响应格式
+func (d *Device) ToResponse() DeviceResponse {
+	return DeviceResponse{
+		ID:        d.ID,
+		Name:      d.Name,
+		Type:      d.Type,
+		Protocol:  d.Protocol,
+		Status:    d.Status,
+		LastSeen:  d.LastSeen,
+		Metadata:  d.Metadata,
+		Config:    d.Config,
+		Firmware:  d.Firmware,
+		Location:  d.Location,
+		CreatedAt: d.CreatedAt,
+		UpdatedAt: d.UpdatedAt,
+	}
+}
+
+// TableName 指定表名
+func (Device) TableName() string {
+	return "devices"
+}
+
+// TableName 指定表名
+func (DeviceEvent) TableName() string {
+	return "device_events"
+}

+ 347 - 0
iot-base-station/internal/device/manager.go

@@ -0,0 +1,347 @@
+package device
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"iot-base-station/pkg/database"
+	"iot-base-station/pkg/security"
+
+	"github.com/go-redis/redis/v8"
+	"go.uber.org/zap"
+	"gorm.io/gorm"
+)
+
+// Manager 设备管理器
+type Manager struct {
+	db     *gorm.DB
+	redis  *redis.Client
+	logger *zap.Logger
+}
+
+// NewManager 创建设备管理器
+func NewManager(db *gorm.DB, redis *redis.Client, logger *zap.Logger) *Manager {
+	return &Manager{
+		db:     db,
+		redis:  redis,
+		logger: logger,
+	}
+}
+
+// CreateDevice 创建设备
+func (m *Manager) CreateDevice(ctx context.Context, req *CreateDeviceRequest) (*DeviceResponse, error) {
+	// 生成设备ID
+	deviceID := generateDeviceID(req.Type)
+
+	// 创建设备对象
+	device := &Device{
+		ID:       deviceID,
+		Name:     req.Name,
+		Type:     req.Type,
+		Protocol: req.Protocol,
+		Status:   StatusOffline,
+		Metadata: req.Metadata,
+		Config:   req.Config,
+		Location: req.Location,
+		Firmware: FirmwareInfo{
+			Version:     "1.0.0",
+			ReleaseDate: time.Now(),
+		},
+	}
+
+	// 保存到数据库
+	if err := m.db.WithContext(ctx).Create(device).Error; err != nil {
+		m.logger.Error("Failed to create device", zap.Error(err))
+		return nil, fmt.Errorf("failed to create device: %w", err)
+	}
+
+	// 创建设备事件
+	event := &DeviceEvent{
+		ID:        generateEventID(),
+		DeviceID:  deviceID,
+		Type:      EventConnect,
+		Severity:  SeverityInfo,
+		Message:   "设备已创建",
+		Timestamp: time.Now(),
+	}
+
+	if err := m.db.WithContext(ctx).Create(event).Error; err != nil {
+		m.logger.Error("Failed to create device event", zap.Error(err))
+	}
+
+	m.logger.Info("Device created", zap.String("device_id", deviceID))
+
+	return &device.ToResponse(), nil
+}
+
+// ListDevices 获取设备列表
+func (m *Manager) ListDevices(ctx context.Context, page, pageSize int, deviceType string) ([]DeviceResponse, int64, error) {
+	var devices []Device
+	var total int64
+
+	query := m.db.WithContext(ctx).Model(&Device{})
+
+	// 按类型筛选
+	if deviceType != "" {
+		query = query.Where("type = ?", deviceType)
+	}
+
+	// 获取总数
+	if err := query.Count(&total).Error; err != nil {
+		m.logger.Error("Failed to count devices", zap.Error(err))
+		return nil, 0, fmt.Errorf("failed to count devices: %w", err)
+	}
+
+	// 分页查询
+	offset := (page - 1) * pageSize
+	if err := query.Offset(offset).Limit(pageSize).Find(&devices).Error; err != nil {
+		m.logger.Error("Failed to list devices", zap.Error(err))
+		return nil, 0, fmt.Errorf("failed to list devices: %w", err)
+	}
+
+	// 转换为响应格式
+	responses := make([]DeviceResponse, len(devices))
+	for i, device := range devices {
+		responses[i] = device.ToResponse()
+	}
+
+	return responses, total, nil
+}
+
+// GetDevice 获取设备详情
+func (m *Manager) GetDevice(ctx context.Context, deviceID string) (*DeviceResponse, error) {
+	var device Device
+
+	if err := m.db.WithContext(ctx).Where("id = ?", deviceID).First(&device).Error; err != nil {
+		if err == gorm.ErrRecordNotFound {
+			return nil, fmt.Errorf("device not found")
+		}
+		m.logger.Error("Failed to get device", zap.Error(err))
+		return nil, fmt.Errorf("failed to get device: %w", err)
+	}
+
+	return &device.ToResponse(), nil
+}
+
+// UpdateDevice 更新设备信息
+func (m *Manager) UpdateDevice(ctx context.Context, deviceID string, req *UpdateDeviceRequest) (*DeviceResponse, error) {
+	var device Device
+
+	// 查询设备
+	if err := m.db.WithContext(ctx).Where("id = ?", deviceID).First(&device).Error; err != nil {
+		if err == gorm.ErrRecordNotFound {
+			return nil, fmt.Errorf("device not found")
+		}
+		m.logger.Error("Failed to get device", zap.Error(err))
+		return nil, fmt.Errorf("failed to get device: %w", err)
+	}
+
+	// 更新字段
+	if req.Name != "" {
+		device.Name = req.Name
+	}
+	if req.Metadata != nil {
+		device.Metadata = req.Metadata
+	}
+	if req.Config.ReportInterval > 0 {
+		device.Config.ReportInterval = req.Config.ReportInterval
+	}
+	if req.Config.Threshold != nil {
+		device.Config.Threshold = req.Config.Threshold
+	}
+	if req.Location.Address != "" {
+		device.Location = req.Location
+	}
+
+	// 保存更新
+	if err := m.db.WithContext(ctx).Save(&device).Error; err != nil {
+		m.logger.Error("Failed to update device", zap.Error(err))
+		return nil, fmt.Errorf("failed to update device: %w", err)
+	}
+
+	// 创建配置更新事件
+	event := &DeviceEvent{
+		ID:        generateEventID(),
+		DeviceID:  deviceID,
+		Type:      EventConfig,
+		Severity:  SeverityInfo,
+		Message:   "设备配置已更新",
+		Timestamp: time.Now(),
+	}
+
+	if err := m.db.WithContext(ctx).Create(event).Error; err != nil {
+		m.logger.Error("Failed to create device event", zap.Error(err))
+	}
+
+	m.logger.Info("Device updated", zap.String("device_id", deviceID))
+
+	return &device.ToResponse(), nil
+}
+
+// DeleteDevice 删除设备
+func (m *Manager) DeleteDevice(ctx context.Context, deviceID string) error {
+	// 软删除设备
+	if err := m.db.WithContext(ctx).Delete(&Device{}, "id = ?", deviceID).Error; err != nil {
+		m.logger.Error("Failed to delete device", zap.Error(err))
+		return fmt.Errorf("failed to delete device: %w", err)
+	}
+
+	m.logger.Info("Device deleted", zap.String("device_id", deviceID))
+
+	return nil
+}
+
+// UpdateDeviceConfig 更新设备配置
+func (m *Manager) UpdateDeviceConfig(ctx context.Context, deviceID string, req *UpdateDeviceConfigRequest) error {
+	var device Device
+
+	// 查询设备
+	if err := m.db.WithContext(ctx).Where("id = ?", deviceID).First(&device).Error; err != nil {
+		if err == gorm.ErrRecordNotFound {
+			return fmt.Errorf("device not found")
+		}
+		m.logger.Error("Failed to get device", zap.Error(err))
+		return fmt.Errorf("failed to get device: %w", err)
+	}
+
+	// 更新配置
+	device.Config = req.Config
+
+	// 保存更新
+	if err := m.db.WithContext(ctx).Save(&device).Error; err != nil {
+		m.logger.Error("Failed to update device config", zap.Error(err))
+		return fmt.Errorf("failed to update device config: %w", err)
+	}
+
+	// 创建配置更新事件
+	event := &DeviceEvent{
+		ID:        generateEventID(),
+		DeviceID:  deviceID,
+		Type:      EventConfig,
+		Severity:  SeverityInfo,
+		Message:   "设备配置已更新",
+		Timestamp: time.Now(),
+	}
+
+	if err := m.db.WithContext(ctx).Create(event).Error; err != nil {
+		m.logger.Error("Failed to create device event", zap.Error(err))
+	}
+
+	m.logger.Info("Device config updated", zap.String("device_id", deviceID))
+
+	return nil
+}
+
+// UpdateFirmware 更新设备固件
+func (m *Manager) UpdateFirmware(ctx context.Context, deviceID string, req *UpdateFirmwareRequest) error {
+	var device Device
+
+	// 查询设备
+	if err := m.db.WithContext(ctx).Where("id = ?", deviceID).First(&device).Error; err != nil {
+		if err == gorm.ErrRecordNotFound {
+			return fmt.Errorf("device not found")
+		}
+		m.logger.Error("Failed to get device", zap.Error(err))
+		return fmt.Errorf("failed to get device: %w", err)
+	}
+
+	// 更新固件信息
+	device.Firmware = FirmwareInfo{
+		Version:     req.Version,
+		URL:         req.URL,
+		Description: req.Description,
+		ReleaseDate: time.Now(),
+	}
+
+	// 更新设备状态为更新中
+	device.Status = StatusUpdating
+
+	// 保存更新
+	if err := m.db.WithContext(ctx).Save(&device).Error; err != nil {
+		m.logger.Error("Failed to update device firmware", zap.Error(err))
+		return fmt.Errorf("failed to update device firmware: %w", err)
+	}
+
+	// 创建固件更新事件
+	event := &DeviceEvent{
+		ID:        generateEventID(),
+		DeviceID:  deviceID,
+		Type:      EventFirmware,
+		Severity:  SeverityInfo,
+		Message:   fmt.Sprintf("固件更新开始,版本: %s", req.Version),
+		Timestamp: time.Now(),
+	}
+
+	if err := m.db.WithContext(ctx).Create(event).Error; err != nil {
+		m.logger.Error("Failed to create device event", zap.Error(err))
+	}
+
+	m.logger.Info("Device firmware update started", 
+		zap.String("device_id", deviceID),
+		zap.String("version", req.Version))
+
+	// TODO: 实际的固件更新逻辑
+	// 这里应该通过协议适配器发送固件更新命令
+
+	return nil
+}
+
+// StartStatusCheck 启动设备状态检查
+func (m *Manager) StartStatusCheck() {
+	ticker := time.NewTicker(5 * time.Minute)
+	defer ticker.Stop()
+
+	for {
+		select {
+		case <-ticker.C:
+			m.checkDeviceStatus()
+		}
+	}
+}
+
+// checkDeviceStatus 检查设备状态
+func (m *Manager) checkDeviceStatus() {
+	ctx := context.Background()
+	var devices []Device
+
+	// 查询所有在线设备
+	if err := m.db.WithContext(ctx).Where("status = ?", StatusOnline).Find(&devices).Error; err != nil {
+		m.logger.Error("Failed to get online devices", zap.Error(err))
+		return
+	}
+
+	// 检查每个设备的最后在线时间
+	now := time.Now()
+	for _, device := range devices {
+		if device.LastSeen != nil && now.Sub(*device.LastSeen) > 10*time.Minute {
+			// 设备离线
+			device.Status = StatusOffline
+			m.db.WithContext(ctx).Save(&device)
+
+			// 创建离线事件
+			event := &DeviceEvent{
+				ID:        generateEventID(),
+				DeviceID:  device.ID,
+				Type:      EventDisconnect,
+				Severity:  SeverityWarning,
+				Message:   "设备离线",
+				Timestamp: now,
+			}
+
+			m.db.WithContext(ctx).Create(event)
+
+			m.logger.Info("Device went offline", zap.String("device_id", device.ID))
+		}
+	}
+}
+
+// generateDeviceID 生成设备ID
+func generateDeviceID(deviceType string) string {
+	return fmt.Sprintf("%s_%d", deviceType, time.Now().UnixNano())
+}
+
+// generateEventID 生成事件ID
+func generateEventID() string {
+	return fmt.Sprintf("event_%d", time.Now().UnixNano())
+}

+ 339 - 0
iot-base-station/internal/protocol/mqtt/adapter.go

@@ -0,0 +1,339 @@
+package mqtt
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"strings"
+	"sync"
+	"time"
+
+	"iot-base-station/internal/device"
+	"iot-base-station/internal/analytics"
+	"iot-base-station/pkg/mqtt"
+
+	MQTT "github.com/eclipse/paho.mqtt.golang"
+	"go.uber.org/zap"
+)
+
+// Adapter MQTT协议适配器
+type Adapter struct {
+	client     mqtt.Client
+	config     Config
+	logger     *zap.Logger
+	dataChan   chan *device.DeviceData
+	eventChan  chan *device.DeviceEvent
+	mu         sync.RWMutex
+	devices    map[string]bool // 在线设备
+}
+
+// Config MQTT配置
+type Config struct {
+	Broker     string `yaml:"broker"`
+	ClientID   string `yaml:"client_id"`
+	Username   string `yaml:"username"`
+	Password   string `yaml:"password"`
+	KeepAlive  int    `yaml:"keep_alive"`
+	QoS        int    `yaml:"qos"`
+	Topics     Topics `yaml:"topics"`
+}
+
+// Topics MQTT主题配置
+type Topics struct {
+	Data      string `yaml:"data"`
+	Event     string `yaml:"event"`
+	Config    string `yaml:"config"`
+	Firmware  string `yaml:"firmware"`
+	Response  string `yaml:"response"`
+	Status    string `yaml:"status"`
+}
+
+// Message MQTT消息
+type Message struct {
+	Topic   string                 `json:"topic"`
+	Payload map[string]interface{} `json:"payload"`
+	QoS     byte                   `json:"qos"`
+	Retained bool                   `json:"retained"`
+}
+
+// NewAdapter 创建MQTT适配器
+func NewAdapter(config Config, logger *zap.Logger) *Adapter {
+	return &Adapter{
+		config:    config,
+		logger:    logger,
+		dataChan:  make(chan *device.DeviceData, 1000),
+		eventChan: make(chan *device.DeviceEvent, 100),
+		devices:   make(map[string]bool),
+	}
+}
+
+// Start 启动MQTT适配器
+func (a *Adapter) Start(ctx context.Context) error {
+	// 创建MQTT客户端
+	opts := MQTT.NewClientOptions()
+	opts.AddBroker(a.config.Broker)
+	opts.SetClientID(a.config.ClientID)
+	opts.SetUsername(a.config.Username)
+	opts.SetPassword(a.config.Password)
+	opts.SetKeepAlive(time.Duration(a.config.KeepAlive) * time.Second)
+	opts.SetDefaultPublishHandler(a.messageHandler)
+	opts.SetOnConnectHandler(a.connectHandler)
+	opts.SetConnectionLostHandler(a.connectLostHandler)
+
+	// 连接MQTT代理
+	client := MQTT.NewClient(opts)
+	if token := client.Connect(); token.Wait() && token.Error() != nil {
+		return fmt.Errorf("failed to connect to MQTT broker: %w", token.Error())
+	}
+
+	a.client = mqtt.NewClient(client)
+
+	// 订阅主题
+	if err := a.subscribeTopics(); err != nil {
+		return fmt.Errorf("failed to subscribe topics: %w", err)
+	}
+
+	a.logger.Info("MQTT adapter started", zap.String("broker", a.config.Broker))
+
+	// 启动消息处理
+	go a.processMessages(ctx)
+
+	return nil
+}
+
+// Stop 停止MQTT适配器
+func (a *Adapter) Stop() error {
+	if a.client != nil {
+		a.client.Disconnect(250)
+	}
+	close(a.dataChan)
+	close(a.eventChan)
+	a.logger.Info("MQTT adapter stopped")
+	return nil
+}
+
+// Name 返回适配器名称
+func (a *Adapter) Name() string {
+	return "mqtt"
+}
+
+// GetDataChannel 获取数据通道
+func (a *Adapter) GetDataChannel() <-chan *device.DeviceData {
+	return a.dataChan
+}
+
+// GetEventChannel 获取事件通道
+func (a *Adapter) GetEventChannel() <-chan *device.DeviceEvent {
+	return a.eventChan
+}
+
+// SendCommand 发送命令到设备
+func (a *Adapter) SendCommand(deviceID, command string, payload map[string]interface{}) error {
+	topic := fmt.Sprintf("%s/%s/%s", a.config.Topics.Config, deviceID, command)
+	
+	message, err := json.Marshal(payload)
+	if err != nil {
+		return fmt.Errorf("failed to marshal command: %w", err)
+	}
+
+	return a.client.Publish(topic, byte(a.config.QoS), false, message)
+}
+
+// SendFirmwareUpdate 发送固件更新命令
+func (a *Adapter) SendFirmwareUpdate(deviceID, version, url string) error {
+	topic := fmt.Sprintf("%s/%s", a.config.Topics.Firmware, deviceID)
+	
+	payload := map[string]interface{}{
+		"version": version,
+		"url":     url,
+		"command": "update",
+	}
+
+	message, err := json.Marshal(payload)
+	if err != nil {
+		return fmt.Errorf("failed to marshal firmware update: %w", err)
+	}
+
+	return a.client.Publish(topic, byte(a.config.QoS), false, message)
+}
+
+// subscribeTopics 订阅MQTT主题
+func (a *Adapter) subscribeTopics() error {
+	topics := []string{
+		a.config.Topics.Data + "/+/+",
+		a.config.Topics.Event + "/+",
+		a.config.Topics.Status + "/+",
+	}
+
+	for _, topic := range topics {
+		if token := a.client.Subscribe(topic, byte(a.config.QoS), nil); token.Wait() && token.Error() != nil {
+			return fmt.Errorf("failed to subscribe to topic %s: %w", topic, token.Error())
+		}
+	}
+
+	return nil
+}
+
+// messageHandler 消息处理器
+func (a *Adapter) messageHandler(client MQTT.Client, msg MQTT.Message) {
+	topic := msg.Topic()
+	payload := msg.Payload()
+
+	a.logger.Debug("Received MQTT message", 
+		zap.String("topic", topic),
+		zap.ByteString("payload", payload))
+
+	// 解析主题
+	parts := strings.Split(topic, "/")
+	if len(parts) < 3 {
+		a.logger.Warn("Invalid topic format", zap.String("topic", topic))
+		return
+	}
+
+	rootTopic := parts[0]
+	deviceID := parts[1]
+
+	// 根据主题类型处理消息
+	switch rootTopic {
+	case a.config.Topics.Data:
+		a.handleDataMessage(deviceID, parts[2], payload)
+	case a.config.Topics.Event:
+		a.handleEventMessage(deviceID, payload)
+	case a.config.Topics.Status:
+		a.handleStatusMessage(deviceID, payload)
+	default:
+		a.logger.Warn("Unknown topic", zap.String("topic", topic))
+	}
+}
+
+// handleDataMessage 处理数据消息
+func (a *Adapter) handleDataMessage(deviceID, dataType string, payload []byte) {
+	var data map[string]interface{}
+	if err := json.Unmarshal(payload, &data); err != nil {
+		a.logger.Error("Failed to unmarshal data message", zap.Error(err))
+		return
+	}
+
+	// 更新设备在线状态
+	a.updateDeviceStatus(deviceID, true)
+
+	// 创建设备数据对象
+	deviceData := &device.DeviceData{
+		DeviceID:  deviceID,
+		Timestamp: time.Now(),
+		Metrics:   data,
+		Quality: device.DataQuality{
+			Good:    true,
+			Source:  "mqtt",
+		},
+	}
+
+	// 发送到数据通道
+	select {
+	case a.dataChan <- deviceData:
+	default:
+		a.logger.Warn("Data channel full, dropping message", zap.String("device_id", deviceID))
+	}
+}
+
+// handleEventMessage 处理事件消息
+func (a *Adapter) handleEventMessage(deviceID string, payload []byte) {
+	var eventData map[string]interface{}
+	if err := json.Unmarshal(payload, &eventData); err != nil {
+		a.logger.Error("Failed to unmarshal event message", zap.Error(err))
+		return
+	}
+
+	// 解析事件类型和严重程度
+	eventType, _ := eventData["type"].(string)
+	severity, _ := eventData["severity"].(string)
+	message, _ := eventData["message"].(string)
+
+	// 创建设备事件对象
+	deviceEvent := &device.DeviceEvent{
+		ID:        generateEventID(),
+		DeviceID:  deviceID,
+		Type:      device.EventType(eventType),
+		Severity:  device.EventSeverity(severity),
+		Message:   message,
+		Data:      eventData,
+		Timestamp: time.Now(),
+	}
+
+	// 发送到事件通道
+	select {
+	case a.eventChan <- deviceEvent:
+	default:
+		a.logger.Warn("Event channel full, dropping message", zap.String("device_id", deviceID))
+	}
+}
+
+// handleStatusMessage 处理状态消息
+func (a *Adapter) handleStatusMessage(deviceID string, payload []byte) {
+	var statusData map[string]interface{}
+	if err := json.Unmarshal(payload, &statusData); err != nil {
+		a.logger.Error("Failed to unmarshal status message", zap.Error(err))
+		return
+	}
+
+	// 解析状态
+	status, _ := statusData["status"].(string)
+	isOnline := status == "online"
+
+	// 更新设备状态
+	a.updateDeviceStatus(deviceID, isOnline)
+
+	// 创建状态事件
+	deviceEvent := &device.DeviceEvent{
+		ID:        generateEventID(),
+		DeviceID:  deviceID,
+		Type:      device.EventConnect,
+		Severity:  device.SeverityInfo,
+		Message:   fmt.Sprintf("设备状态: %s", status),
+		Data:      statusData,
+		Timestamp: time.Now(),
+	}
+
+	// 发送到事件通道
+	select {
+	case a.eventChan <- deviceEvent:
+	default:
+		a.logger.Warn("Event channel full, dropping message", zap.String("device_id", deviceID))
+	}
+}
+
+// updateDeviceStatus 更新设备状态
+func (a *Adapter) updateDeviceStatus(deviceID string, isOnline bool) {
+	a.mu.Lock()
+	defer a.mu.Unlock()
+
+	a.devices[deviceID] = isOnline
+}
+
+// processMessages 处理消息
+func (a *Adapter) processMessages(ctx context.Context) {
+	for {
+		select {
+		case <-ctx.Done():
+			return
+		default:
+			// 这里可以添加消息批处理逻辑
+			time.Sleep(100 * time.Millisecond)
+		}
+	}
+}
+
+// connectHandler 连接处理器
+func (a *Adapter) connectHandler(client MQTT.Client) {
+	a.logger.Info("Connected to MQTT broker")
+}
+
+// connectLostHandler 连接丢失处理器
+func (a *Adapter) connectLostHandler(client MQTT.Client, err error) {
+	a.logger.Error("Connection to MQTT broker lost", zap.Error(err))
+}
+
+// generateEventID 生成事件ID
+func generateEventID() string {
+	return fmt.Sprintf("mqtt_event_%d", time.Now().UnixNano())
+}

+ 1 - 0
iot-base-station/migrations/000001_create_devices_table.down.sql

@@ -0,0 +1 @@
+DROP TABLE IF EXISTS devices;

+ 20 - 0
iot-base-station/migrations/000001_create_devices_table.up.sql

@@ -0,0 +1,20 @@
+CREATE TABLE IF NOT EXISTS devices (
+    id VARCHAR(255) PRIMARY KEY,
+    name VARCHAR(255) NOT NULL,
+    type VARCHAR(100) NOT NULL,
+    protocol VARCHAR(50) NOT NULL,
+    status VARCHAR(20) DEFAULT 'offline',
+    last_seen TIMESTAMP,
+    metadata JSONB,
+    config JSONB,
+    firmware JSONB,
+    location JSONB,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    deleted_at TIMESTAMP
+);
+
+CREATE INDEX idx_devices_type ON devices(type);
+CREATE INDEX idx_devices_status ON devices(status);
+CREATE INDEX idx_devices_protocol ON devices(protocol);
+CREATE INDEX idx_devices_deleted_at ON devices(deleted_at);

+ 1 - 0
iot-base-station/migrations/000002_create_device_events_table.down.sql

@@ -0,0 +1 @@
+DROP TABLE IF EXISTS device_events;

+ 19 - 0
iot-base-station/migrations/000002_create_device_events_table.up.sql

@@ -0,0 +1,19 @@
+CREATE TABLE IF NOT EXISTS device_events (
+    id VARCHAR(255) PRIMARY KEY,
+    device_id VARCHAR(255) NOT NULL,
+    type VARCHAR(50) NOT NULL,
+    severity VARCHAR(20) NOT NULL,
+    message TEXT,
+    data JSONB,
+    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    acked BOOLEAN DEFAULT FALSE,
+    acked_by VARCHAR(255),
+    acked_at TIMESTAMP,
+    FOREIGN KEY (device_id) REFERENCES devices(id) ON DELETE CASCADE
+);
+
+CREATE INDEX idx_device_events_device_id ON device_events(device_id);
+CREATE INDEX idx_device_events_type ON device_events(type);
+CREATE INDEX idx_device_events_severity ON device_events(severity);
+CREATE INDEX idx_device_events_timestamp ON device_events(timestamp);
+CREATE INDEX idx_device_events_acked ON device_events(acked);

+ 131 - 0
iot-base-station/scripts/health-check.sh

@@ -0,0 +1,131 @@
+#!/bin/bash
+
+# 物联网基站服务健康检查脚本
+
+set -e
+
+echo "=== 物联网基站服务健康检查 ==="
+
+# 检查PostgreSQL
+echo "检查PostgreSQL..."
+if docker-compose exec -T postgres pg_isready -U postgres > /dev/null 2>&1; then
+    echo "✓ PostgreSQL: 健康"
+    # 检查数据库连接
+    if docker-compose exec -T postgres psql -U postgres -d iot_base_station -c "SELECT 1;" > /dev/null 2>&1; then
+        echo "  - 数据库连接: 正常"
+    else
+        echo "  - 数据库连接: 异常"
+    fi
+else
+    echo "✗ PostgreSQL: 不可用"
+fi
+
+# 检查InfluxDB
+echo "检查InfluxDB..."
+if curl -s http://localhost:8086/health > /dev/null 2>&1; then
+    echo "✓ InfluxDB: 健康"
+    # 检查组织是否存在
+    if curl -s -H "Authorization: Token influxdb-token" "http://localhost:8086/api/v2/orgs" | grep -q "iot-org"; then
+        echo "  - 组织配置: 正常"
+    else
+        echo "  - 组织配置: 异常"
+    fi
+else
+    echo "✗ InfluxDB: 不可用"
+fi
+
+# 检查Redis
+echo "检查Redis..."
+if docker-compose exec -T redis redis-cli ping > /dev/null 2>&1; then
+    echo "✓ Redis: 健康"
+    # 检查内存使用
+    MEMORY=$(docker-compose exec -T redis redis-cli info memory | grep used_memory_human | cut -d: -f2 | tr -d '\r')
+    echo "  - 内存使用: $MEMORY"
+elif redis-cli ping > /dev/null 2>&1; then
+    echo "✓ Redis (本地): 健康"
+    MEMORY=$(redis-cli info memory | grep used_memory_human | cut -d: -f2 | tr -d '\r')
+    echo "  - 内存使用: $MEMORY"
+else
+    echo "✗ Redis: 不可用"
+fi
+
+# 检查NATS
+echo "检查NATS..."
+if curl -s http://localhost:8222/varz > /dev/null 2>&1; then
+    echo "✓ NATS: 健康"
+    # 检查连接数
+    CONNECTIONS=$(curl -s http://localhost:8222/varz | jq -r '.connections // 0')
+    echo "  - 当前连接数: $CONNECTIONS"
+else
+    echo "✗ NATS: 不可用"
+fi
+
+# 检查MQTT
+echo "检查MQTT..."
+if docker-compose exec -T mqtt mosquitto_pub -h localhost -t '$SYS/broker/version' -m 'test' > /dev/null 2>&1; then
+    echo "✓ MQTT: 健康"
+    # 检查连接数
+    CONNECTIONS=$(docker-compose exec -T mqtt mosquitto_sub -h localhost -t '$SYS/broker/connections' -C 1 | grep -o '[0-9]\+' || echo "0")
+    echo "  - 当前连接数: $CONNECTIONS"
+elif mosquitto_pub -h localhost -t '$SYS/broker/version' -m 'test' > /dev/null 2>&1; then
+    echo "✓ MQTT (本地): 健康"
+else
+    echo "✗ MQTT: 不可用"
+fi
+
+# 检查Grafana
+echo "检查Grafana..."
+if curl -s http://localhost:3000/api/health > /dev/null 2>&1; then
+    echo "✓ Grafana: 健康"
+else
+    echo "✗ Grafana: 不可用"
+fi
+
+# 检查Prometheus
+echo "检查Prometheus..."
+if curl -s http://localhost:9090/-/healthy > /dev/null 2>&1; then
+    echo "✓ Prometheus: 健康"
+    # 检查目标数量
+    TARGETS=$(curl -s http://localhost:9090/api/v1/targets | jq -r '.data.activeTargets | length')
+    echo "  - 活跃目标数: $TARGETS"
+else
+    echo "✗ Prometheus: 不可用"
+fi
+
+# 检查应用服务
+echo "检查应用服务..."
+if curl -s http://localhost:8080/health > /dev/null 2>&1; then
+    echo "✓ 主服务器: 健康"
+else
+    echo "✗ 主服务器: 不可用"
+fi
+
+if curl -s http://localhost:8081/health > /dev/null 2>&1; then
+    echo "✓ 数据网关: 健康"
+else
+    echo "✗ 数据网关: 不可用"
+fi
+
+if curl -s http://localhost:8082/health > /dev/null 2>&1; then
+    echo "✓ 监控服务: 健康"
+else
+    echo "✗ 监控服务: 不可用"
+fi
+
+echo ""
+echo "=== 健康检查完成 ==="
+
+# 显示资源使用情况
+echo ""
+echo "=== 资源使用情况 ==="
+docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
+
+# 显示磁盘使用情况
+echo ""
+echo "=== 磁盘使用情况 ==="
+df -h | grep -E "(Filesystem|/dev/)"
+
+# 显示网络连接
+echo ""
+echo "=== 网络连接 ==="
+netstat -tuln | grep -E "(LISTEN|5432|8086|6379|4222|1883|3000|9090|8080|8081|8082)" || echo "无法获取网络连接信息"

+ 202 - 0
iot-base-station/scripts/setup-dev.sh

@@ -0,0 +1,202 @@
+#!/bin/bash
+
+# 物联网基站本地开发环境设置脚本
+
+set -e
+
+echo "=== 物联网基站本地开发环境设置 ==="
+
+# 检查Docker是否安装
+if ! command -v docker &> /dev/null; then
+    echo "错误: Docker未安装,请先安装Docker"
+    exit 1
+fi
+
+# 检查Docker Compose是否安装
+if ! command -v docker-compose &> /dev/null; then
+    echo "错误: Docker Compose未安装,请先安装Docker Compose"
+    exit 1
+fi
+
+# 检查Go是否安装
+if ! command -v go &> /dev/null; then
+    echo "错误: Go未安装,请先安装Go 1.19+"
+    exit 1
+fi
+
+# 检查Go版本
+GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//')
+REQUIRED_VERSION="1.19"
+
+if [ "$(printf '%s\n' "$REQUIRED_VERSION" "$GO_VERSION" | sort -V | head -n1)" != "$REQUIRED_VERSION" ]; then
+    echo "错误: Go版本过低,需要Go $REQUIRED_VERSION 或更高版本,当前版本: $GO_VERSION"
+    exit 1
+fi
+
+echo "✓ 环境检查通过"
+
+# 创建开发配置文件
+if [ ! -f config/config.dev.yaml ]; then
+    echo "创建开发配置文件..."
+    cp config/config.yaml config/config.dev.yaml
+    
+    # 修改开发配置
+    sed -i.bak 's/mode: "debug"/mode: "debug"/' config/config.dev.yaml
+    sed -i.bak 's/output: "logs\/app.log"/output: "stdout"/' config/config.dev.yaml
+    sed -i.bak 's/level: "info"/level: "debug"/' config/config.dev.yaml
+    
+    echo "✓ 开发配置文件已创建"
+else
+    echo "✓ 开发配置文件已存在"
+fi
+
+# 创建环境变量文件
+if [ ! -f .env ]; then
+    echo "创建环境变量文件..."
+    cat > .env << EOF
+CONFIG_PATH=config/config.dev.yaml
+GIN_MODE=debug
+EOF
+    echo "✓ 环境变量文件已创建"
+else
+    echo "✓ 环境变量文件已存在"
+fi
+
+# 创建必要的目录
+echo "创建必要的目录..."
+mkdir -p logs
+mkdir -p uploads
+mkdir -p tmp
+echo "✓ 目录创建完成"
+
+# 启动基础服务
+echo "启动基础服务..."
+docker-compose up -d postgres influxdb redis nats mqtt
+
+# 等待服务启动
+echo "等待服务启动..."
+sleep 10
+
+# 检查服务状态
+echo "检查服务状态..."
+docker-compose ps
+
+# 创建数据库
+echo "创建数据库..."
+docker-compose exec -T postgres psql -U postgres -c "CREATE DATABASE iot_base_station;" || echo "数据库可能已存在"
+
+# 运行数据库迁移
+echo "运行数据库迁移..."
+go run cmd/migrate/main.go up
+
+# 安装开发工具
+echo "安装开发工具..."
+go install github.com/cosmtrek/air@latest
+go install github.com/go-delve/delve/cmd/dlv@latest
+go install golang.org/x/tools/cmd/goimports@latest
+go install golang.org/x/lint/golint@latest
+
+# 创建VS Code配置
+if [ ! -d .vscode ]; then
+    echo "创建VS Code配置..."
+    mkdir -p .vscode
+    
+    cat > .vscode/launch.json << EOF
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Launch Server",
+            "type": "go",
+            "request": "launch",
+            "mode": "debug",
+            "program": "\${workspaceFolder}/cmd/server/main.go",
+            "env": {
+                "CONFIG_PATH": "config/config.dev.yaml"
+            }
+        },
+        {
+            "name": "Launch Gateway",
+            "type": "go",
+            "request": "launch",
+            "mode": "debug",
+            "program": "\${workspaceFolder}/cmd/gateway/main.go",
+            "env": {
+                "CONFIG_PATH": "config/config.dev.yaml"
+            }
+        }
+    ]
+}
+EOF
+
+    cat > .vscode/settings.json << EOF
+{
+    "go.useLanguageServer": true,
+    "go.formatTool": "goimports",
+    "go.lintTool": "golint",
+    "go.lintOnSave": "package",
+    "editor.formatOnSave": true,
+    "editor.codeActionsOnSave": {
+        "source.organizeImports": true
+    }
+}
+EOF
+
+    echo "✓ VS Code配置已创建"
+else
+    echo "✓ VS Code配置已存在"
+fi
+
+# 创建Pre-commit钩子
+if [ ! -f .pre-commit-config.yaml ]; then
+    echo "创建Pre-commit钩子..."
+    cat > .pre-commit-config.yaml << EOF
+repos:
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.4.0
+    hooks:
+      - id: trailing-whitespace
+      - id: end-of-file-fixer
+      - id: check-yaml
+      - id: check-added-large-files
+
+  - repo: https://github.com/tekwizely/pre-commit-golang
+    rev: v1.0.0-rc.1
+    hooks:
+      - id: go-fmt
+      - id: go-vet-mod
+      - id: go-mod-tidy
+EOF
+
+    # 安装pre-commit
+    if command -v pip &> /dev/null; then
+        pip install pre-commit
+        pre-commit install
+        echo "✓ Pre-commit钩子已安装"
+    else
+        echo "警告: pip未安装,跳过pre-commit安装"
+    fi
+else
+    echo "✓ Pre-commit配置已存在"
+fi
+
+# 显示下一步操作
+echo ""
+echo "=== 开发环境设置完成 ==="
+echo ""
+echo "下一步操作:"
+echo "1. 启动主服务器: go run cmd/server/main.go"
+echo "2. 启动数据网关: go run cmd/gateway/main.go"
+echo "3. 启动监控服务: go run cmd/monitor/main.go"
+echo "4. 运行设备模拟器: go run simulations/main.go"
+echo ""
+echo "或者使用热重载: air -c .air.toml"
+echo ""
+echo "访问应用:"
+echo "- 管理平台: http://localhost:8080"
+echo "- Grafana: http://localhost:3000 (admin/admin)"
+echo "- InfluxDB: http://localhost:8086"
+echo ""
+echo "测试API:"
+echo "curl -X GET http://localhost:8080/health"
+echo ""

+ 84 - 0
iot-base-station/scripts/start-infrastructure.sh

@@ -0,0 +1,84 @@
+#!/bin/bash
+
+# 物联网基站基础服务启动脚本
+
+set -e
+
+echo "=== 启动物联网基站基础服务 ==="
+
+# 检查Docker是否运行
+if ! docker info > /dev/null 2>&1; then
+    echo "错误: Docker未运行,请先启动Docker"
+    exit 1
+fi
+
+# 检查Docker Compose是否安装
+if ! command -v docker-compose &> /dev/null; then
+    echo "错误: Docker Compose未安装,请先安装Docker Compose"
+    exit 1
+fi
+
+# 检查Redis是否已运行
+REDIS_RUNNING=false
+if docker ps --format "table {{.Names}}" | grep -q "redis"; then
+    echo "✓ 检测到Redis容器已运行"
+    REDIS_RUNNING=true
+elif redis-cli ping > /dev/null 2>&1; then
+    echo "✓ 检测到本地Redis服务已运行"
+    REDIS_RUNNING=true
+else
+    echo "! Redis服务未运行,将启动Docker中的Redis"
+fi
+
+# 启动服务
+if [ "$REDIS_RUNNING" = true ]; then
+    echo "启动除Redis外的服务..."
+    docker-compose -f docker-compose-without-redis.yml up -d
+else
+    echo "启动所有服务..."
+    docker-compose up -d
+fi
+
+# 等待服务启动
+echo "等待服务启动..."
+sleep 15
+
+# 检查服务状态
+echo "检查服务状态..."
+docker-compose ps
+
+# 初始化数据库
+echo "初始化数据库..."
+if docker-compose exec -T postgres pg_isready -U postgres > /dev/null 2>&1; then
+    docker-compose exec -T postgres psql -U postgres -c "CREATE DATABASE iot_base_station;" || echo "数据库可能已存在"
+    
+    # 运行数据库迁移
+    echo "运行数据库迁移..."
+    go run cmd/migrate/main.go up
+else
+    echo "警告: PostgreSQL未就绪,请手动运行迁移"
+fi
+
+# 显示服务信息
+echo ""
+echo "=== 服务信息 ==="
+echo "PostgreSQL: localhost:5432"
+echo "InfluxDB: http://localhost:8086"
+echo "Redis: localhost:6379"
+echo "NATS: localhost:4222"
+echo "MQTT: localhost:1883"
+echo "Grafana: http://localhost:3000 (admin/admin)"
+echo "Prometheus: http://localhost:9090"
+
+# 显示下一步操作
+echo ""
+echo "=== 下一步操作 ==="
+echo "1. 启动主服务器: go run cmd/server/main.go"
+echo "2. 启动数据网关: go run cmd/gateway/main.go"
+echo "3. 启动监控服务: go run cmd/monitor/main.go"
+echo "4. 运行设备模拟器: go run simulations/main.go"
+echo ""
+echo "或者使用热重载: air -c .air.toml"
+echo ""
+echo "测试API: curl -X GET http://localhost:8080/health"
+echo ""

+ 209 - 0
iot-base-station/simulations/devices/temperature_sensor.go

@@ -0,0 +1,209 @@
+package devices
+
+import (
+	"encoding/json"
+	"fmt"
+	"math/rand"
+	"time"
+
+	"iot-base-station/pkg/mqtt"
+)
+
+// TemperatureSensor 温度传感器模拟器
+type TemperatureSensor struct {
+	ID          string
+	Name        string
+	Location    string
+	MinTemp     float64
+	MaxTemp     float64
+	Interval    time.Duration
+	client      mqtt.Client
+	topic       string
+	running     bool
+	stopChan    chan bool
+}
+
+// TemperatureData 温度数据
+type TemperatureData struct {
+	DeviceID    string    `json:"device_id"`
+	Temperature float64   `json:"temperature"`
+	Humidity    float64   `json:"humidity"`
+	Timestamp   time.Time `json:"timestamp"`
+	Location    string    `json:"location"`
+	Status      string    `json:"status"`
+}
+
+// NewTemperatureSensor 创建温度传感器模拟器
+func NewTemperatureSensor(id, name, location string, minTemp, maxTemp float64, interval time.Duration) *TemperatureSensor {
+	return &TemperatureSensor{
+		ID:       id,
+		Name:     name,
+		Location: location,
+		MinTemp:  minTemp,
+		MaxTemp:  maxTemp,
+		Interval: interval,
+		topic:    fmt.Sprintf("iot/data/%s/temperature", id),
+		stopChan: make(chan bool),
+	}
+}
+
+// Connect 连接到MQTT代理
+func (s *TemperatureSensor) Connect(broker string) error {
+	// 创建MQTT客户端
+	opts := mqtt.NewClientOptions()
+	opts.AddBroker(broker)
+	opts.SetClientID(s.ID)
+	opts.SetCleanSession(true)
+
+	// 连接MQTT代理
+	client := mqtt.NewClient(opts)
+	if token := client.Connect(); token.Wait() && token.Error() != nil {
+		return fmt.Errorf("failed to connect to MQTT broker: %w", token.Error())
+	}
+
+	s.client = client
+	return nil
+}
+
+// Start 启动传感器
+func (s *TemperatureSensor) Start() {
+	if s.running {
+		return
+	}
+
+	s.running = true
+	go s.run()
+}
+
+// Stop 停止传感器
+func (s *TemperatureSensor) Stop() {
+	if !s.running {
+		return
+	}
+
+	s.running = false
+	s.stopChan <- true
+}
+
+// run 运行传感器
+func (s *TemperatureSensor) run() {
+	ticker := time.NewTicker(s.Interval)
+	defer ticker.Stop()
+
+	// 发送初始状态
+	s.sendStatus("online")
+
+	for {
+		select {
+		case <-ticker.C:
+			// 生成随机温度数据
+			temp := s.MinTemp + rand.Float64()*(s.MaxTemp-s.MinTemp)
+			humidity := 30.0 + rand.Float64()*40.0 // 30-70%湿度
+
+			// 创建温度数据
+			data := TemperatureData{
+				DeviceID:    s.ID,
+				Temperature: temp,
+				Humidity:    humidity,
+				Timestamp:   time.Now(),
+				Location:    s.Location,
+				Status:      "normal",
+			}
+
+			// 检查温度是否异常
+			if temp > s.MaxTemp*0.9 || temp < s.MinTemp*1.1 {
+				data.Status = "warning"
+				s.sendAlert(fmt.Sprintf("温度异常: %.2f°C", temp))
+			}
+
+			// 发送数据
+			s.sendData(data)
+
+		case <-s.stopChan:
+			// 发送离线状态
+			s.sendStatus("offline")
+			return
+		}
+	}
+}
+
+// sendData 发送数据
+func (s *TemperatureSensor) sendData(data TemperatureData) {
+	if s.client == nil {
+		return
+	}
+
+	payload, err := json.Marshal(data)
+	if err != nil {
+		fmt.Printf("Failed to marshal temperature data: %v\n", err)
+		return
+	}
+
+	if err := s.client.Publish(s.topic, 1, false, payload); err != nil {
+		fmt.Printf("Failed to publish temperature data: %v\n", err)
+		return
+	}
+
+	fmt.Printf("Sent temperature data from %s: %.2f°C\n", s.ID, data.Temperature)
+}
+
+// sendStatus 发送状态
+func (s *TemperatureSensor) sendStatus(status string) {
+	if s.client == nil {
+		return
+	}
+
+	topic := fmt.Sprintf("iot/status/%s", s.ID)
+	payload := map[string]interface{}{
+		"status":    status,
+		"timestamp": time.Now(),
+	}
+
+	data, err := json.Marshal(payload)
+	if err != nil {
+		fmt.Printf("Failed to marshal status data: %v\n", err)
+		return
+	}
+
+	if err := s.client.Publish(topic, 1, true, data); err != nil {
+		fmt.Printf("Failed to publish status data: %v\n", err)
+		return
+	}
+
+	fmt.Printf("Sent status from %s: %s\n", s.ID, status)
+}
+
+// sendAlert 发送告警
+func (s *TemperatureSensor) sendAlert(message string) {
+	if s.client == nil {
+		return
+	}
+
+	topic := fmt.Sprintf("iot/event/%s", s.ID)
+	payload := map[string]interface{}{
+		"type":      "alert",
+		"severity":  "warning",
+		"message":   message,
+		"timestamp": time.Now(),
+	}
+
+	data, err := json.Marshal(payload)
+	if err != nil {
+		fmt.Printf("Failed to marshal alert data: %v\n", err)
+		return
+	}
+
+	if err := s.client.Publish(topic, 1, false, data); err != nil {
+		fmt.Printf("Failed to publish alert data: %v\n", err)
+		return
+	}
+
+	fmt.Printf("Sent alert from %s: %s\n", s.ID, message)
+}
+
+// Disconnect 断开连接
+func (s *TemperatureSensor) Disconnect() {
+	if s.client != nil {
+		s.client.Disconnect(250)
+	}
+}

+ 59 - 0
iot-base-station/simulations/main.go

@@ -0,0 +1,59 @@
+package main
+
+import (
+	"flag"
+	"log"
+	"os"
+	"os/signal"
+	"syscall"
+	"time"
+
+	"iot-base-station/simulations/devices"
+)
+
+var (
+	broker    = flag.String("broker", "tcp://localhost:1883", "MQTT broker address")
+	count     = flag.Int("count", 5, "Number of sensors to simulate")
+	interval  = flag.Duration("interval", 30*time.Second, "Data reporting interval")
+)
+
+func main() {
+	flag.Parse()
+
+	// 创建温度传感器模拟器
+	sensors := make([]*devices.TemperatureSensor, *count)
+	for i := 0; i < *count; i++ {
+		id := fmt.Sprintf("temp_sensor_%02d", i+1)
+		name := fmt.Sprintf("温度传感器 %02d", i+1)
+		location := fmt.Sprintf("机房%d", (i%3)+1)
+		
+		sensor := devices.NewTemperatureSensor(id, name, location, 15.0, 35.0, *interval)
+		sensors[i] = sensor
+
+		// 连接到MQTT代理
+		if err := sensor.Connect(*broker); err != nil {
+			log.Fatalf("Failed to connect sensor %s: %v", id, err)
+		}
+
+		// 启动传感器
+		sensor.Start()
+		log.Printf("Started sensor: %s", id)
+	}
+
+	log.Printf("Started %d temperature sensors", *count)
+
+	// 等待中断信号
+	quit := make(chan os.Signal, 1)
+	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+	<-quit
+
+	log.Println("Shutting down sensors...")
+
+	// 停止所有传感器
+	for _, sensor := range sensors {
+		sensor.Stop()
+		sensor.Disconnect()
+	}
+
+	log.Println("All sensors stopped")
+}

+ 0 - 1
test1.txt

@@ -1 +0,0 @@
-1111

+ 53 - 0
web-training/Dockerfile

@@ -0,0 +1,53 @@
+# 构建阶段
+FROM golang:1.19-alpine AS builder
+
+# 设置工作目录
+WORKDIR /app
+
+# 安装必要的包
+RUN apk add --no-cache git
+
+# 复制go mod文件
+COPY go.mod go.sum ./
+
+# 下载依赖
+RUN go mod download
+
+# 复制源代码
+COPY . .
+
+# 构建应用
+RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main cmd/server/main.go
+
+# 运行阶段
+FROM alpine:latest
+
+# 安装ca证书
+RUN apk --no-cache add ca-certificates
+
+# 创建非root用户
+RUN addgroup -g 1001 -S appgroup && \
+    adduser -u 1001 -S appuser -G appgroup
+
+# 设置工作目录
+WORKDIR /app
+
+# 从构建阶段复制二进制文件
+COPY --from=builder /app/main .
+
+# 复制配置文件和静态资源
+COPY --from=builder /app/config ./config
+COPY --from=builder /app/web ./web
+
+# 创建必要的目录
+RUN mkdir -p uploads logs && \
+    chown -R appuser:appgroup /app
+
+# 切换到非root用户
+USER appuser
+
+# 暴露端口
+EXPOSE 8080
+
+# 运行应用
+CMD ["./main"]

+ 246 - 0
web-training/README.md

@@ -0,0 +1,246 @@
+# Go Web开发特训项目
+
+## 项目概述
+这是一个基于Go语言的Web开发特训项目,包含从基础到高级的Web开发技术栈,通过实际项目练习掌握现代Web应用开发技能。
+
+## 项目结构
+
+```
+web-training/
+├── README.md                 # 项目说明
+├── go.mod                    # 依赖管理
+├── go.sum                    # 依赖锁定
+├── config/                   # 配置文件
+│   ├── config.yaml          # 应用配置
+│   └── config.go            # 配置加载
+├── cmd/                      # 应用入口
+│   ├── server/              # Web服务器
+│   │   └── main.go
+│   └── admin/               # 后台管理
+│       └── main.go
+├── internal/                 # 内部包
+│   ├── config/              # 配置管理
+│   ├── handler/             # HTTP处理器
+│   │   ├── user.go
+│   │   ├── product.go
+│   │   ├── order.go
+│   │   └── upload.go
+│   ├── middleware/          # 中间件
+│   │   ├── auth.go
+│   │   ├── cors.go
+│   │   ├── logger.go
+│   │   └── ratelimit.go
+│   ├── model/               # 数据模型
+│   │   ├── user.go
+│   │   ├── product.go
+│   │   ├── order.go
+│   │   └── cart.go
+│   ├── repository/          # 数据访问层
+│   │   ├── user.go
+│   │   ├── product.go
+│   │   └── order.go
+│   ├── service/             # 业务逻辑层
+│   │   ├── user.go
+│   │   ├── product.go
+│   │   ├── order.go
+│   │   └── auth.go
+│   └── utils/               # 工具函数
+│       ├── response.go
+│       ├── validation.go
+│       └── pagination.go
+├── pkg/                      # 公共包
+│   ├── auth/                # 认证模块
+│   │   ├── jwt.go
+│   │   └── password.go
+│   ├── cache/               # 缓存模块
+│   │   └── redis.go
+│   ├── database/            # 数据库模块
+│   │   └── mysql.go
+│   ├── storage/             # 存储模块
+│   │   └── local.go
+│   └── websocket/           # WebSocket模块
+│       └── hub.go
+├── web/                      # 前端资源
+│   ├── static/              # 静态文件
+│   │   ├── css/
+│   │   ├── js/
+│   │   └── images/
+│   └── templates/           # 模板文件
+│       ├── index.html
+│       ├── login.html
+│       └── dashboard.html
+├── uploads/                  # 上传文件目录
+├── scripts/                  # 脚本文件
+│   ├── build.sh
+│   └── deploy.sh
+├── docs/                     # 文档
+│   ├── api.md               # API文档
+│   └── deployment.md        # 部署文档
+├── tests/                    # 测试文件
+│   ├── integration/
+│   └── unit/
+└── docker-compose.yml        # Docker配置
+```
+
+## 技术栈
+
+### 后端技术
+- **Web框架**: Gin
+- **数据库**: MySQL
+- **ORM**: GORM
+- **缓存**: Redis
+- **认证**: JWT
+- **配置管理**: Viper
+- **日志**: Zap
+- **WebSocket**: Gorilla WebSocket
+
+### 开发工具
+- **测试**: Go test + Testify
+- **文档**: Swagger
+- **部署**: Docker
+- **监控**: Prometheus + Grafana
+
+## 快速开始
+
+### 1. 环境准备
+```bash
+# 安装Go 1.19+
+# 安装MySQL 8.0+
+# 安装Redis 6.0+
+```
+
+### 2. 克隆项目
+```bash
+git clone <repository-url>
+cd web-training
+```
+
+### 3. 安装依赖
+```bash
+go mod download
+```
+
+### 4. 配置数据库
+```bash
+# 创建数据库
+mysql -u root -p
+CREATE DATABASE web_training;
+
+# 导入初始数据
+mysql -u root -p web_training < scripts/init.sql
+```
+
+### 5. 启动服务
+```bash
+# 启动Web服务器
+go run cmd/server/main.go
+
+# 或使用Docker
+docker-compose up -d
+```
+
+### 6. 访问应用
+- Web应用: http://localhost:8080
+- API文档: http://localhost:8080/swagger/index.html
+- 后台管理: http://localhost:8080/admin
+
+## 学习路径
+
+### 第一阶段:基础Web开发 (1-2周)
+- Gin框架基础
+- 路由与中间件
+- 数据绑定与验证
+- 模板渲染
+
+### 第二阶段:前后端分离 (2-3周)
+- RESTful API设计
+- JWT认证
+- CORS处理
+- 统一响应格式
+
+### 第三阶段:高级特性 (2-3周)
+- WebSocket实时通信
+- 文件上传处理
+- 缓存策略
+- 性能优化
+
+### 第四阶段:项目实战 (3-4周)
+- 电商平台开发
+- 用户管理系统
+- 商品管理
+- 订单处理
+
+## API接口
+
+### 用户管理
+- `POST /api/v1/register` - 用户注册
+- `POST /api/v1/login` - 用户登录
+- `GET /api/v1/users` - 获取用户列表
+- `GET /api/v1/users/:id` - 获取用户详情
+- `PUT /api/v1/users/:id` - 更新用户信息
+- `DELETE /api/v1/users/:id` - 删除用户
+
+### 商品管理
+- `GET /api/v1/products` - 获取商品列表
+- `POST /api/v1/products` - 创建商品
+- `GET /api/v1/products/:id` - 获取商品详情
+- `PUT /api/v1/products/:id` - 更新商品
+- `DELETE /api/v1/products/:id` - 删除商品
+
+### 订单管理
+- `GET /api/v1/orders` - 获取订单列表
+- `POST /api/v1/orders` - 创建订单
+- `GET /api/v1/orders/:id` - 获取订单详情
+- `PUT /api/v1/orders/:id` - 更新订单状态
+
+## 测试
+
+### 运行单元测试
+```bash
+go test ./...
+```
+
+### 运行集成测试
+```bash
+go test -tags=integration ./tests/integration/...
+```
+
+### 生成测试覆盖率报告
+```bash
+go test -coverprofile=coverage.out ./...
+go tool cover -html=coverage.out
+```
+
+## 部署
+
+### Docker部署
+```bash
+# 构建镜像
+docker build -t web-training .
+
+# 运行容器
+docker run -p 8080:8080 web-training
+```
+
+### 使用Docker Compose
+```bash
+docker-compose up -d
+```
+
+## 贡献指南
+
+1. Fork 项目
+2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
+3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
+4. 推送到分支 (`git push origin feature/AmazingFeature`)
+5. 打开 Pull Request
+
+## 许可证
+
+本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情
+
+## 联系方式
+
+如有问题或建议,请提交 Issue 或联系项目维护者
+
+祝您学习愉快!

+ 156 - 0
web-training/cmd/server/main.go

@@ -0,0 +1,156 @@
+package main
+
+import (
+	"log"
+	"web-training/config"
+	"web-training/internal/handler"
+	"web-training/internal/middleware"
+	"web-training/pkg/database"
+	"web-training/pkg/cache"
+	"web-training/pkg/auth"
+	"web-training/pkg/storage"
+	"web-training/pkg/websocket"
+
+	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
+)
+
+func main() {
+	// 加载配置
+	cfg, err := config.LoadConfig("config/config.yaml")
+	if err != nil {
+		log.Fatalf("Failed to load config: %v", err)
+	}
+
+	// 初始化日志
+	logger, err := initLogger(cfg.Log)
+	if err != nil {
+		log.Fatalf("Failed to initialize logger: %v", err)
+	}
+	defer logger.Sync()
+
+	// 初始化数据库
+	db, err := database.InitMySQL(cfg.Database)
+	if err != nil {
+		logger.Fatal("Failed to initialize database", zap.Error(err))
+	}
+
+	// 初始化Redis
+	redisClient, err := cache.InitRedis(cfg.Redis)
+	if err != nil {
+		logger.Fatal("Failed to initialize Redis", zap.Error(err))
+	}
+
+	// 初始化JWT服务
+	jwtService := auth.NewJWTService(cfg.JWT.Secret, cfg.JWT.Expire)
+
+	// 初始化存储服务
+	storageService := storage.NewLocalStorage(cfg.Upload.Path, cfg.Upload.MaxSize, cfg.Upload.AllowedTypes)
+
+	// 初始化WebSocket Hub
+	wsHub := websocket.NewHub()
+	go wsHub.Run()
+
+	// 设置Gin模式
+	gin.SetMode(cfg.Server.Mode)
+
+	// 创建Gin引擎
+	r := gin.New()
+
+	// 添加全局中间件
+	r.Use(middleware.LoggerMiddleware(logger))
+	r.Use(middleware.RecoveryMiddleware(logger))
+	r.Use(middleware.CORSMiddleware())
+	r.Use(middleware.RateLimitMiddleware(100)) // 限制每秒100个请求
+
+	// 初始化处理器
+	userHandler := handler.NewUserHandler(db, jwtService)
+	productHandler := handler.NewProductHandler(db, redisClient, storageService)
+	orderHandler := handler.NewOrderHandler(db)
+	uploadHandler := handler.NewUploadHandler(storageService)
+	wsHandler := handler.NewWebSocketHandler(wsHub)
+
+	// 设置路由
+	setupRoutes(r, userHandler, productHandler, orderHandler, uploadHandler, wsHandler, jwtService)
+
+	// 启动服务器
+	logger.Info("Starting server", zap.String("port", cfg.Server.Port))
+	if err := r.Run(":" + cfg.Server.Port); err != nil {
+		logger.Fatal("Failed to start server", zap.Error(err))
+	}
+}
+
+func setupRoutes(r *gin.Engine, 
+	userHandler *handler.UserHandler,
+	productHandler *handler.ProductHandler,
+	orderHandler *handler.OrderHandler,
+	uploadHandler *handler.UploadHandler,
+	wsHandler *handler.WebSocketHandler,
+	jwtService *auth.JWTService) {
+	
+	// 静态文件服务
+	r.Static("/static", "./web/static")
+	r.LoadHTMLGlob("web/templates/*")
+
+	// 首页
+	r.GET("/", func(c *gin.Context) {
+		c.HTML(200, "index.html", gin.H{
+			"title": "Go Web Training",
+		})
+	})
+
+	// API路由组
+	api := r.Group("/api/v1")
+	{
+		// 公开路由
+		api.POST("/register", userHandler.Register)
+		api.POST("/login", userHandler.Login)
+		
+		// 需要认证的路由
+		authGroup := api.Group("/")
+		authGroup.Use(middleware.AuthMiddleware(jwtService))
+		{
+			// 用户管理
+			authGroup.GET("/users", userHandler.ListUsers)
+			authGroup.GET("/users/:id", userHandler.GetUser)
+			authGroup.PUT("/users/:id", userHandler.UpdateUser)
+			authGroup.DELETE("/users/:id", userHandler.DeleteUser)
+			
+			// 商品管理
+			authGroup.GET("/products", productHandler.ListProducts)
+			authGroup.POST("/products", productHandler.CreateProduct)
+			authGroup.GET("/products/:id", productHandler.GetProduct)
+			authGroup.PUT("/products/:id", productHandler.UpdateProduct)
+			authGroup.DELETE("/products/:id", productHandler.DeleteProduct)
+			
+			// 订单管理
+			authGroup.GET("/orders", orderHandler.ListOrders)
+			authGroup.POST("/orders", orderHandler.CreateOrder)
+			authGroup.GET("/orders/:id", orderHandler.GetOrder)
+			authGroup.PUT("/orders/:id", orderHandler.UpdateOrder)
+			
+			// 文件上传
+			authGroup.POST("/upload", uploadHandler.UploadFile)
+		}
+	}
+
+	// WebSocket路由
+	r.GET("/ws", wsHandler.HandleWebSocket)
+}
+
+func initLogger(logConfig config.LogConfig) (*zap.Logger, error) {
+	var logger *zap.Logger
+	var err error
+
+	if logConfig.Level == "debug" {
+		logger, err = zap.NewDevelopment()
+	} else {
+		logger, err = zap.NewProduction()
+	}
+
+	if err != nil {
+		return nil, err
+	}
+
+	return logger, nil
+}

+ 134 - 0
web-training/config/config.go

@@ -0,0 +1,134 @@
+package config
+
+import (
+	"log"
+	"github.com/spf13/viper"
+)
+
+// Config 应用配置结构
+type Config struct {
+	Server   ServerConfig   `mapstructure:"server"`
+	Database DatabaseConfig `mapstructure:"database"`
+	Redis    RedisConfig    `mapstructure:"redis"`
+	JWT      JWTConfig      `mapstructure:"jwt"`
+	Upload   UploadConfig   `mapstructure:"upload"`
+	Log      LogConfig      `mapstructure:"log"`
+}
+
+// ServerConfig 服务器配置
+type ServerConfig struct {
+	Port         string `mapstructure:"port"`
+	Mode         string `mapstructure:"mode"`
+	ReadTimeout  int    `mapstructure:"read_timeout"`
+	WriteTimeout int    `mapstructure:"write_timeout"`
+}
+
+// DatabaseConfig 数据库配置
+type DatabaseConfig struct {
+	Host            string `mapstructure:"host"`
+	Port            string `mapstructure:"port"`
+	User            string `mapstructure:"user"`
+	Password        string `mapstructure:"password"`
+	DBName          string `mapstructure:"dbname"`
+	MaxOpenConns    int    `mapstructure:"max_open_conns"`
+	MaxIdleConns    int    `mapstructure:"max_idle_conns"`
+	ConnMaxLifetime int    `mapstructure:"conn_max_lifetime"`
+}
+
+// RedisConfig Redis配置
+type RedisConfig struct {
+	Host     string `mapstructure:"host"`
+	Port     string `mapstructure:"port"`
+	Password string `mapstructure:"password"`
+	DB       int    `mapstructure:"db"`
+	PoolSize int    `mapstructure:"pool_size"`
+}
+
+// JWTConfig JWT配置
+type JWTConfig struct {
+	Secret string `mapstructure:"secret"`
+	Expire int    `mapstructure:"expire"`
+}
+
+// UploadConfig 文件上传配置
+type UploadConfig struct {
+	Path         string   `mapstructure:"path"`
+	MaxSize      int      `mapstructure:"max_size"`
+	AllowedTypes []string `mapstructure:"allowed_types"`
+}
+
+// LogConfig 日志配置
+type LogConfig struct {
+	Level      string `mapstructure:"level"`
+	Output     string `mapstructure:"output"`
+	MaxSize    int    `mapstructure:"max_size"`
+	MaxBackups int    `mapstructure:"max_backups"`
+	MaxAge     int    `mapstructure:"max_age"`
+}
+
+// LoadConfig 加载配置文件
+func LoadConfig(configPath string) (*Config, error) {
+	viper.SetConfigFile(configPath)
+	viper.SetConfigType("yaml")
+
+	// 设置默认值
+	setDefaults()
+
+	// 环境变量覆盖
+	viper.AutomaticEnv()
+
+	if err := viper.ReadInConfig(); err != nil {
+		log.Printf("Error reading config file: %v", err)
+		return nil, err
+	}
+
+	var config Config
+	if err := viper.Unmarshal(&config); err != nil {
+		log.Printf("Error unmarshaling config: %v", err)
+		return nil, err
+	}
+
+	return &config, nil
+}
+
+// setDefaults 设置默认配置值
+func setDefaults() {
+	// 服务器默认配置
+	viper.SetDefault("server.port", "8080")
+	viper.SetDefault("server.mode", "debug")
+	viper.SetDefault("server.read_timeout", 60)
+	viper.SetDefault("server.write_timeout", 60)
+
+	// 数据库默认配置
+	viper.SetDefault("database.host", "localhost")
+	viper.SetDefault("database.port", "3306")
+	viper.SetDefault("database.user", "root")
+	viper.SetDefault("database.password", "password")
+	viper.SetDefault("database.dbname", "web_training")
+	viper.SetDefault("database.max_open_conns", 100)
+	viper.SetDefault("database.max_idle_conns", 10)
+	viper.SetDefault("database.conn_max_lifetime", 3600)
+
+	// Redis默认配置
+	viper.SetDefault("redis.host", "localhost")
+	viper.SetDefault("redis.port", "6379")
+	viper.SetDefault("redis.password", "")
+	viper.SetDefault("redis.db", 0)
+	viper.SetDefault("redis.pool_size", 10)
+
+	// JWT默认配置
+	viper.SetDefault("jwt.secret", "your-secret-key")
+	viper.SetDefault("jwt.expire", 86400)
+
+	// 上传默认配置
+	viper.SetDefault("upload.path", "./uploads")
+	viper.SetDefault("upload.max_size", 10)
+	viper.SetDefault("upload.allowed_types", []string{"jpg", "jpeg", "png", "gif"})
+
+	// 日志默认配置
+	viper.SetDefault("log.level", "info")
+	viper.SetDefault("log.output", "logs/app.log")
+	viper.SetDefault("log.max_size", 100)
+	viper.SetDefault("log.max_backups", 3)
+	viper.SetDefault("log.max_age", 28)
+}

+ 38 - 0
web-training/config/config.yaml

@@ -0,0 +1,38 @@
+server:
+  port: "8080"
+  mode: "debug"  # debug, release, test
+  read_timeout: 60
+  write_timeout: 60
+
+database:
+  host: "localhost"
+  port: "3306"
+  user: "root"
+  password: "password"
+  dbname: "web_training"
+  max_open_conns: 100
+  max_idle_conns: 10
+  conn_max_lifetime: 3600
+
+redis:
+  host: "localhost"
+  port: "6379"
+  password: ""
+  db: 0
+  pool_size: 10
+
+jwt:
+  secret: "your-secret-key"
+  expire: 86400  # 24 hours
+
+upload:
+  path: "./uploads"
+  max_size: 10  # MB
+  allowed_types: ["jpg", "jpeg", "png", "gif"]
+
+log:
+  level: "info"
+  output: "logs/app.log"
+  max_size: 100  # MB
+  max_backups: 3
+  max_age: 28  # days

+ 64 - 0
web-training/docker-compose.yml

@@ -0,0 +1,64 @@
+version: '3.8'
+
+services:
+  app:
+    build: .
+    ports:
+      - "8080:8080"
+    environment:
+      - DB_HOST=mysql
+      - DB_PORT=3306
+      - DB_USER=root
+      - DB_PASSWORD=rootpassword
+      - DB_NAME=web_training
+      - REDIS_HOST=redis
+      - REDIS_PORT=6379
+    depends_on:
+      - mysql
+      - redis
+    volumes:
+      - ./uploads:/app/uploads
+      - ./logs:/app/logs
+    networks:
+      - web-training-network
+
+  mysql:
+    image: mysql:8.0
+    environment:
+      - MYSQL_ROOT_PASSWORD=rootpassword
+      - MYSQL_DATABASE=web_training
+      - MYSQL_USER=webuser
+      - MYSQL_PASSWORD=webpassword
+    ports:
+      - "3306:3306"
+    volumes:
+      - mysql_data:/var/lib/mysql
+      - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql
+    networks:
+      - web-training-network
+
+  redis:
+    image: redis:6.2-alpine
+    ports:
+      - "6379:6379"
+    volumes:
+      - redis_data:/data
+    networks:
+      - web-training-network
+
+  adminer:
+    image: adminer
+    ports:
+      - "8081:8080"
+    depends_on:
+      - mysql
+    networks:
+      - web-training-network
+
+volumes:
+  mysql_data:
+  redis_data:
+
+networks:
+  web-training-network:
+    driver: bridge

+ 728 - 0
web-training/docs/api.md

@@ -0,0 +1,728 @@
+# API 文档
+
+## 概述
+
+本文档描述了Go Web训练项目的RESTful API接口。所有API都遵循REST设计原则,使用JSON格式进行数据交换。
+
+## 基础信息
+
+- **基础URL**: `http://localhost:8080/api/v1`
+- **认证方式**: JWT Bearer Token
+- **内容类型**: `application/json`
+- **字符编码**: UTF-8
+
+## 通用响应格式
+
+### 成功响应
+
+```json
+{
+  "code": 200,
+  "message": "操作成功",
+  "data": {
+    // 响应数据
+  }
+}
+```
+
+### 分页响应
+
+```json
+{
+  "code": 200,
+  "message": "获取成功",
+  "data": [
+    // 数据列表
+  ],
+  "meta": {
+    "page": 1,
+    "page_size": 10,
+    "total": 100,
+    "total_page": 10
+  }
+}
+```
+
+### 错误响应
+
+```json
+{
+  "code": 400,
+  "message": "请求参数错误",
+  "data": {
+    "details": "具体错误信息"
+  }
+}
+```
+
+## 认证
+
+### 用户注册
+
+**POST** `/register`
+
+注册新用户账户。
+
+**请求体**:
+```json
+{
+  "username": "testuser",
+  "email": "[email protected]",
+  "password": "password123",
+  "first_name": "张",
+  "last_name": "三",
+  "phone": "13800138000",
+  "address": "北京市朝阳区"
+}
+```
+
+**响应**:
+```json
+{
+  "code": 201,
+  "message": "注册成功",
+  "data": {
+    "id": 1,
+    "username": "testuser",
+    "email": "[email protected]",
+    "first_name": "张",
+    "last_name": "三",
+    "phone": "13800138000",
+    "address": "北京市朝阳区",
+    "is_active": true,
+    "role": "user",
+    "created_at": "2023-01-01T00:00:00Z",
+    "updated_at": "2023-01-01T00:00:00Z"
+  }
+}
+```
+
+### 用户登录
+
+**POST** `/login`
+
+用户登录获取访问令牌。
+
+**请求体**:
+```json
+{
+  "username": "testuser",
+  "password": "password123"
+}
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "登录成功",
+  "data": {
+    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
+    "user": {
+      "id": 1,
+      "username": "testuser",
+      "email": "[email protected]",
+      "first_name": "张",
+      "last_name": "三",
+      "is_active": true,
+      "role": "user",
+      "created_at": "2023-01-01T00:00:00Z",
+      "updated_at": "2023-01-01T00:00:00Z"
+    }
+  }
+}
+```
+
+## 用户管理
+
+### 获取用户列表
+
+**GET** `/users`
+
+获取用户列表,支持分页和搜索。
+
+**查询参数**:
+- `page` (int, 可选): 页码,默认为1
+- `page_size` (int, 可选): 每页数量,默认为10
+- `search` (string, 可选): 搜索关键词
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "获取成功",
+  "data": [
+    {
+      "id": 1,
+      "username": "testuser",
+      "email": "[email protected]",
+      "first_name": "张",
+      "last_name": "三",
+      "is_active": true,
+      "role": "user",
+      "created_at": "2023-01-01T00:00:00Z",
+      "updated_at": "2023-01-01T00:00:00Z"
+    }
+  ],
+  "meta": {
+    "page": 1,
+    "page_size": 10,
+    "total": 1,
+    "total_page": 1
+  }
+}
+```
+
+### 获取用户详情
+
+**GET** `/users/{id}`
+
+获取指定用户的详细信息。
+
+**路径参数**:
+- `id` (int): 用户ID
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "获取成功",
+  "data": {
+    "id": 1,
+    "username": "testuser",
+    "email": "[email protected]",
+    "first_name": "张",
+    "last_name": "三",
+    "phone": "13800138000",
+    "address": "北京市朝阳区",
+    "is_active": true,
+    "role": "user",
+    "created_at": "2023-01-01T00:00:00Z",
+    "updated_at": "2023-01-01T00:00:00Z"
+  }
+}
+```
+
+### 更新用户信息
+
+**PUT** `/users/{id}`
+
+更新指定用户的信息。
+
+**路径参数**:
+- `id` (int): 用户ID
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**请求体**:
+```json
+{
+  "first_name": "李",
+  "last_name": "四",
+  "phone": "13900139000",
+  "address": "上海市浦东新区"
+}
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "更新成功",
+  "data": {
+    "id": 1,
+    "username": "testuser",
+    "email": "[email protected]",
+    "first_name": "李",
+    "last_name": "四",
+    "phone": "13900139000",
+    "address": "上海市浦东新区",
+    "is_active": true,
+    "role": "user",
+    "created_at": "2023-01-01T00:00:00Z",
+    "updated_at": "2023-01-02T00:00:00Z"
+  }
+}
+```
+
+### 删除用户
+
+**DELETE** `/users/{id}`
+
+删除指定用户。
+
+**路径参数**:
+- `id` (int): 用户ID
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "删除成功",
+  "data": null
+}
+```
+
+## 商品管理
+
+### 获取商品列表
+
+**GET** `/products`
+
+获取商品列表,支持分页和搜索。
+
+**查询参数**:
+- `page` (int, 可选): 页码,默认为1
+- `page_size` (int, 可选): 每页数量,默认为10
+- `search` (string, 可选): 搜索关键词
+- `category_id` (int, 可选): 分类ID
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "获取成功",
+  "data": [
+    {
+      "id": 1,
+      "name": "智能手机",
+      "description": "最新款智能手机,配备高清摄像头和长续航电池",
+      "price": 2999.00,
+      "stock": 100,
+      "category_id": 1,
+      "image": "/uploads/products/1.jpg",
+      "is_active": true,
+      "created_at": "2023-01-01T00:00:00Z",
+      "updated_at": "2023-01-01T00:00:00Z"
+    }
+  ],
+  "meta": {
+    "page": 1,
+    "page_size": 10,
+    "total": 1,
+    "total_page": 1
+  }
+}
+```
+
+### 创建商品
+
+**POST** `/products`
+
+创建新商品。
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**请求体**:
+```json
+{
+  "name": "平板电脑",
+  "description": "轻薄便携,高清屏幕",
+  "price": 1999.00,
+  "stock": 50,
+  "category_id": 1
+}
+```
+
+**响应**:
+```json
+{
+  "code": 201,
+  "message": "创建成功",
+  "data": {
+    "id": 2,
+    "name": "平板电脑",
+    "description": "轻薄便携,高清屏幕",
+    "price": 1999.00,
+    "stock": 50,
+    "category_id": 1,
+    "image": "",
+    "is_active": true,
+    "created_at": "2023-01-01T00:00:00Z",
+    "updated_at": "2023-01-01T00:00:00Z"
+  }
+}
+```
+
+### 获取商品详情
+
+**GET** `/products/{id}`
+
+获取指定商品的详细信息。
+
+**路径参数**:
+- `id` (int): 商品ID
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "获取成功",
+  "data": {
+    "id": 1,
+    "name": "智能手机",
+    "description": "最新款智能手机,配备高清摄像头和长续航电池",
+    "price": 2999.00,
+    "stock": 100,
+    "category_id": 1,
+    "image": "/uploads/products/1.jpg",
+    "is_active": true,
+    "created_at": "2023-01-01T00:00:00Z",
+    "updated_at": "2023-01-01T00:00:00Z"
+  }
+}
+```
+
+### 更新商品
+
+**PUT** `/products/{id}`
+
+更新指定商品的信息。
+
+**路径参数**:
+- `id` (int): 商品ID
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**请求体**:
+```json
+{
+  "name": "智能手机Pro",
+  "description": "升级版智能手机,更强大的性能",
+  "price": 3299.00,
+  "stock": 80
+}
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "更新成功",
+  "data": {
+    "id": 1,
+    "name": "智能手机Pro",
+    "description": "升级版智能手机,更强大的性能",
+    "price": 3299.00,
+    "stock": 80,
+    "category_id": 1,
+    "image": "/uploads/products/1.jpg",
+    "is_active": true,
+    "created_at": "2023-01-01T00:00:00Z",
+    "updated_at": "2023-01-02T00:00:00Z"
+  }
+}
+```
+
+### 删除商品
+
+**DELETE** `/products/{id}`
+
+删除指定商品。
+
+**路径参数**:
+- `id` (int): 商品ID
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "删除成功",
+  "data": null
+}
+```
+
+## 订单管理
+
+### 获取订单列表
+
+**GET** `/orders`
+
+获取当前用户的订单列表,支持分页。
+
+**查询参数**:
+- `page` (int, 可选): 页码,默认为1
+- `page_size` (int, 可选): 每页数量,默认为10
+- `status` (string, 可选): 订单状态筛选
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "获取成功",
+  "data": [
+    {
+      "id": 1,
+      "order_number": "ORD20230101001",
+      "total_amount": 2999.00,
+      "status": "pending",
+      "shipping_address": "北京市朝阳区",
+      "payment_method": "alipay",
+      "payment_status": "pending",
+      "created_at": "2023-01-01T00:00:00Z",
+      "updated_at": "2023-01-01T00:00:00Z"
+    }
+  ],
+  "meta": {
+    "page": 1,
+    "page_size": 10,
+    "total": 1,
+    "total_page": 1
+  }
+}
+```
+
+### 创建订单
+
+**POST** `/orders`
+
+创建新订单。
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**请求体**:
+```json
+{
+  "items": [
+    {
+      "product_id": 1,
+      "quantity": 1
+    }
+  ],
+  "shipping_address": "北京市朝阳区",
+  "payment_method": "alipay"
+}
+```
+
+**响应**:
+```json
+{
+  "code": 201,
+  "message": "创建成功",
+  "data": {
+    "id": 1,
+    "order_number": "ORD20230101001",
+    "total_amount": 2999.00,
+    "status": "pending",
+    "shipping_address": "北京市朝阳区",
+    "payment_method": "alipay",
+    "payment_status": "pending",
+    "created_at": "2023-01-01T00:00:00Z",
+    "updated_at": "2023-01-01T00:00:00Z"
+  }
+}
+```
+
+### 获取订单详情
+
+**GET** `/orders/{id}`
+
+获取指定订单的详细信息。
+
+**路径参数**:
+- `id` (int): 订单ID
+
+**请求头**:
+```
+Authorization: Bearer <token>
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "获取成功",
+  "data": {
+    "id": 1,
+    "order_number": "ORD20230101001",
+    "total_amount": 2999.00,
+    "status": "pending",
+    "shipping_address": "北京市朝阳区",
+    "payment_method": "alipay",
+    "payment_status": "pending",
+    "created_at": "2023-01-01T00:00:00Z",
+    "updated_at": "2023-01-01T00:00:00Z",
+    "items": [
+      {
+        "id": 1,
+        "product_id": 1,
+        "product_name": "智能手机",
+        "quantity": 1,
+        "price": 2999.00
+      }
+    ]
+  }
+}
+```
+
+## 文件上传
+
+### 上传文件
+
+**POST** `/upload`
+
+上传文件到服务器。
+
+**请求头**:
+```
+Authorization: Bearer <token>
+Content-Type: multipart/form-data
+```
+
+**请求体**:
+```
+file: <binary>
+```
+
+**响应**:
+```json
+{
+  "code": 200,
+  "message": "上传成功",
+  "data": {
+    "filename": "uploads/abc123.jpg",
+    "original_name": "image.jpg",
+    "size": 1024000,
+    "content_type": "image/jpeg"
+  }
+}
+```
+
+## WebSocket
+
+### 实时通信
+
+**WebSocket** `/ws`
+
+建立WebSocket连接进行实时通信。
+
+**连接参数**:
+- `token` (string): JWT认证令牌
+
+**消息格式**:
+```json
+{
+  "type": "message",
+  "data": {
+    "content": "Hello, World!",
+    "timestamp": "2023-01-01T00:00:00Z"
+  }
+}
+```
+
+## 错误代码
+
+| 代码 | 说明 |
+|------|------|
+| 400 | 请求参数错误 |
+| 401 | 未授权访问 |
+| 403 | 权限不足 |
+| 404 | 资源不存在 |
+| 429 | 请求过于频繁 |
+| 500 | 服务器内部错误 |
+
+## 使用示例
+
+### JavaScript示例
+
+```javascript
+// 登录
+fetch('/api/v1/login', {
+  method: 'POST',
+  headers: {
+    'Content-Type': 'application/json'
+  },
+  body: JSON.stringify({
+    username: 'testuser',
+    password: 'password123'
+  })
+})
+.then(response => response.json())
+.then(data => {
+  if (data.code === 200) {
+    // 保存令牌
+    localStorage.setItem('token', data.data.token);
+    
+    // 使用令牌获取用户列表
+    fetch('/api/v1/users', {
+      headers: {
+        'Authorization': `Bearer ${data.data.token}`
+      }
+    })
+    .then(response => response.json())
+    .then(users => {
+      console.log(users);
+    });
+  }
+});
+```
+
+### cURL示例
+
+```bash
+# 登录
+curl -X POST http://localhost:8080/api/v1/login \
+  -H "Content-Type: application/json" \
+  -d '{"username":"testuser","password":"password123"}'
+
+# 获取用户列表
+curl -X GET http://localhost:8080/api/v1/users \
+  -H "Authorization: Bearer <token>"
+```
+
+## 更新日志
+
+### v1.0.0 (2023-01-01)
+- 初始版本发布
+- 实现用户管理API
+- 实现商品管理API
+- 实现订单管理API
+- 实现文件上传API
+- 实现WebSocket通信

+ 21 - 0
web-training/go.mod

@@ -0,0 +1,21 @@
+module web-training
+
+go 1.19
+
+require (
+	github.com/gin-gonic/gin v1.9.0
+	github.com/golang-jwt/jwt/v5 v5.0.0
+	github.com/go-sql-driver/mysql v1.7.0
+	github.com/spf13/viper v1.15.0
+	github.com/go-redis/redis/v8 v8.11.5
+	github.com/gorilla/websocket v1.5.0
+	gorm.io/driver/mysql v1.5.1
+	gorm.io/gorm v1.25.2
+	golang.org/x/crypto v0.8.0
+	golang.org/x/time v0.3.0
+	github.com/swaggo/gin-swagger v1.6.0
+	github.com/swaggo/files v1.0.1
+	github.com/swaggo/swag v1.16.1
+	go.uber.org/zap v1.24.0
+	github.com/stretchr/testify v1.8.4
+)

+ 211 - 0
web-training/internal/handler/user.go

@@ -0,0 +1,211 @@
+package handler
+
+import (
+	"net/http"
+	"web-training/internal/model"
+	"web-training/internal/service"
+	"web-training/pkg/auth"
+	"web-training/internal/utils"
+
+	"github.com/gin-gonic/gin"
+)
+
+// UserHandler 用户处理器
+type UserHandler struct {
+	userService *service.UserService
+	jwtService  *auth.JWTService
+}
+
+// NewUserHandler 创建用户处理器
+func NewUserHandler(db interface{}, jwtService *auth.JWTService) *UserHandler {
+	// 这里应该注入UserService,暂时简化处理
+	userService := service.NewUserService(db)
+	return &UserHandler{
+		userService: userService,
+		jwtService:  jwtService,
+	}
+}
+
+// Register 用户注册
+// @Summary 用户注册
+// @Tags 用户管理
+// @Accept json
+// @Produce json
+// @Param user body model.CreateUserRequest true "用户信息"
+// @Success 201 {object} utils.APIResponse{data=model.UserResponse}
+// @Failure 400 {object} utils.APIResponse
+// @Failure 500 {object} utils.APIResponse
+// @Router /api/v1/register [post]
+func (h *UserHandler) Register(c *gin.Context) {
+	var req model.CreateUserRequest
+	if err := c.ShouldBindJSON(&req); err != nil {
+		utils.ErrorResponse(c, http.StatusBadRequest, "请求参数错误", err.Error())
+		return
+	}
+
+	user, err := h.userService.CreateUser(req)
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusInternalServerError, "注册失败", err.Error())
+		return
+	}
+
+	utils.SuccessResponse(c, http.StatusCreated, "注册成功", user.ToResponse())
+}
+
+// Login 用户登录
+// @Summary 用户登录
+// @Tags 用户管理
+// @Accept json
+// @Produce json
+// @Param credentials body model.LoginRequest true "登录凭证"
+// @Success 200 {object} utils.APIResponse{data=model.LoginResponse}
+// @Failure 400 {object} utils.APIResponse
+// @Failure 401 {object} utils.APIResponse
+// @Failure 500 {object} utils.APIResponse
+// @Router /api/v1/login [post]
+func (h *UserHandler) Login(c *gin.Context) {
+	var req model.LoginRequest
+	if err := c.ShouldBindJSON(&req); err != nil {
+		utils.ErrorResponse(c, http.StatusBadRequest, "请求参数错误", err.Error())
+		return
+	}
+
+	user, err := h.userService.Authenticate(req.Username, req.Password)
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusUnauthorized, "用户名或密码错误", err.Error())
+		return
+	}
+
+	// 生成JWT令牌
+	token, err := h.jwtService.GenerateToken(user.ID, []string{user.Role})
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusInternalServerError, "生成令牌失败", err.Error())
+		return
+	}
+
+	loginResp := model.LoginResponse{
+		Token: token,
+		User:  user.ToResponse(),
+	}
+
+	utils.SuccessResponse(c, http.StatusOK, "登录成功", loginResp)
+}
+
+// ListUsers 获取用户列表
+// @Summary 获取用户列表
+// @Tags 用户管理
+// @Accept json
+// @Produce json
+// @Param page query int false "页码" default(1)
+// @Param page_size query int false "每页数量" default(10)
+// @Param search query string false "搜索关键词"
+// @Success 200 {object} utils.APIResponse{data=[]model.UserResponse,meta=utils.MetaInfo}
+// @Failure 401 {object} utils.APIResponse
+// @Failure 500 {object} utils.APIResponse
+// @Router /api/v1/users [get]
+func (h *UserHandler) ListUsers(c *gin.Context) {
+	page, pageSize := utils.GetPaginationParams(c)
+	search := c.Query("search")
+
+	users, total, err := h.userService.ListUsers(page, pageSize, search)
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusInternalServerError, "获取用户列表失败", err.Error())
+		return
+	}
+
+	// 转换为响应格式
+	userResponses := make([]model.UserResponse, len(users))
+	for i, user := range users {
+		userResponses[i] = user.ToResponse()
+	}
+
+	utils.PaginatedResponse(c, http.StatusOK, "获取成功", userResponses, page, pageSize, total)
+}
+
+// GetUser 获取用户详情
+// @Summary 获取用户详情
+// @Tags 用户管理
+// @Accept json
+// @Produce json
+// @Param id path int true "用户ID"
+// @Success 200 {object} utils.APIResponse{data=model.UserResponse}
+// @Failure 400 {object} utils.APIResponse
+// @Failure 404 {object} utils.APIResponse
+// @Failure 500 {object} utils.APIResponse
+// @Router /api/v1/users/{id} [get]
+func (h *UserHandler) GetUser(c *gin.Context) {
+	id, err := utils.GetIDParam(c)
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusBadRequest, "无效的用户ID", err.Error())
+		return
+	}
+
+	user, err := h.userService.GetUserByID(id)
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusNotFound, "用户不存在", err.Error())
+		return
+	}
+
+	utils.SuccessResponse(c, http.StatusOK, "获取成功", user.ToResponse())
+}
+
+// UpdateUser 更新用户信息
+// @Summary 更新用户信息
+// @Tags 用户管理
+// @Accept json
+// @Produce json
+// @Param id path int true "用户ID"
+// @Param user body model.UpdateUserRequest true "用户信息"
+// @Success 200 {object} utils.APIResponse{data=model.UserResponse}
+// @Failure 400 {object} utils.APIResponse
+// @Failure 404 {object} utils.APIResponse
+// @Failure 500 {object} utils.APIResponse
+// @Router /api/v1/users/{id} [put]
+func (h *UserHandler) UpdateUser(c *gin.Context) {
+	id, err := utils.GetIDParam(c)
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusBadRequest, "无效的用户ID", err.Error())
+		return
+	}
+
+	var req model.UpdateUserRequest
+	if err := c.ShouldBindJSON(&req); err != nil {
+		utils.ErrorResponse(c, http.StatusBadRequest, "请求参数错误", err.Error())
+		return
+	}
+
+	user, err := h.userService.UpdateUser(id, req)
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusInternalServerError, "更新用户失败", err.Error())
+		return
+	}
+
+	utils.SuccessResponse(c, http.StatusOK, "更新成功", user.ToResponse())
+}
+
+// DeleteUser 删除用户
+// @Summary 删除用户
+// @Tags 用户管理
+// @Accept json
+// @Produce json
+// @Param id path int true "用户ID"
+// @Success 200 {object} utils.APIResponse
+// @Failure 400 {object} utils.APIResponse
+// @Failure 404 {object} utils.APIResponse
+// @Failure 500 {object} utils.APIResponse
+// @Router /api/v1/users/{id} [delete]
+func (h *UserHandler) DeleteUser(c *gin.Context) {
+	id, err := utils.GetIDParam(c)
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusBadRequest, "无效的用户ID", err.Error())
+		return
+	}
+
+	err = h.userService.DeleteUser(id)
+	if err != nil {
+		utils.ErrorResponse(c, http.StatusInternalServerError, "删除用户失败", err.Error())
+		return
+	}
+
+	utils.SuccessResponse(c, http.StatusOK, "删除成功", nil)
+}

+ 155 - 0
web-training/internal/middleware/auth.go

@@ -0,0 +1,155 @@
+package middleware
+
+import (
+	"net/http"
+	"strings"
+	"web-training/pkg/auth"
+	"web-training/internal/utils"
+
+	"github.com/gin-gonic/gin"
+)
+
+// AuthMiddleware JWT认证中间件
+func AuthMiddleware(jwtService *auth.JWTService) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		// 从请求头获取Authorization
+		authHeader := c.GetHeader("Authorization")
+		if authHeader == "" {
+			utils.ErrorResponse(c, http.StatusUnauthorized, "缺少认证令牌", "")
+			c.Abort()
+			return
+		}
+
+		// 检查Bearer前缀
+		parts := strings.Split(authHeader, " ")
+		if len(parts) != 2 || parts[0] != "Bearer" {
+			utils.ErrorResponse(c, http.StatusUnauthorized, "令牌格式错误", "")
+			c.Abort()
+			return
+		}
+
+		// 验证令牌
+		token := parts[1]
+		claims, err := jwtService.ValidateToken(token)
+		if err != nil {
+			utils.ErrorResponse(c, http.StatusUnauthorized, "无效令牌", err.Error())
+			c.Abort()
+			return
+		}
+
+		// 将用户信息存储到上下文
+		c.Set("userID", claims.UserID)
+		c.Set("userRoles", claims.Roles)
+		c.Set("claims", claims)
+
+		c.Next()
+	}
+}
+
+// RoleBasedAuthMiddleware 基于角色的权限控制中间件
+func RoleBasedAuthMiddleware(requiredRoles ...string) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		// 获取用户角色
+		userRoles, exists := c.Get("userRoles")
+		if !exists {
+			utils.ErrorResponse(c, http.StatusForbidden, "权限不足", "无法获取用户角色")
+			c.Abort()
+			return
+		}
+
+		// 检查用户角色是否包含所需角色
+		userRolesSlice, ok := userRoles.([]string)
+		if !ok {
+			utils.ErrorResponse(c, http.StatusForbidden, "权限不足", "角色格式错误")
+			c.Abort()
+			return
+		}
+
+		hasPermission := false
+		for _, requiredRole := range requiredRoles {
+			for _, userRole := range userRolesSlice {
+				if userRole == requiredRole {
+					hasPermission = true
+					break
+				}
+			}
+			if hasPermission {
+				break
+			}
+		}
+
+		if !hasPermission {
+			utils.ErrorResponse(c, http.StatusForbidden, "权限不足", "角色权限不足")
+			c.Abort()
+			return
+		}
+
+		c.Next()
+	}
+}
+
+// AdminOnlyMiddleware 仅管理员访问中间件
+func AdminOnlyMiddleware() gin.HandlerFunc {
+	return RoleBasedAuthMiddleware("admin")
+}
+
+// SelfOrAdminMiddleware 用户本人或管理员访问中间件
+func SelfOrAdminMiddleware() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		userID, exists := c.Get("userID")
+		if !exists {
+			utils.ErrorResponse(c, http.StatusForbidden, "权限不足", "无法获取用户ID")
+			c.Abort()
+			return
+		}
+
+		userRoles, exists := c.Get("userRoles")
+		if !exists {
+			utils.ErrorResponse(c, http.StatusForbidden, "权限不足", "无法获取用户角色")
+			c.Abort()
+			return
+		}
+
+		// 获取请求中的用户ID
+		paramID := c.Param("id")
+		if paramID == "" {
+			utils.ErrorResponse(c, http.StatusBadRequest, "请求参数错误", "缺少用户ID参数")
+			c.Abort()
+			return
+		}
+
+		// 检查是否是管理员
+		userRolesSlice, ok := userRoles.([]string)
+		if !ok {
+			utils.ErrorResponse(c, http.StatusForbidden, "权限不足", "角色格式错误")
+			c.Abort()
+			return
+		}
+
+		isAdmin := false
+		for _, role := range userRolesSlice {
+			if role == "admin" {
+				isAdmin = true
+				break
+			}
+		}
+
+		// 如果不是管理员,检查是否是用户本人
+		if !isAdmin {
+			userIDUint, ok := userID.(uint)
+			if !ok {
+				utils.ErrorResponse(c, http.StatusForbidden, "权限不足", "用户ID格式错误")
+				c.Abort()
+				return
+			}
+
+			if paramID != string(rune(userIDUint)) {
+				utils.ErrorResponse(c, http.StatusForbidden, "权限不足", "只能访问自己的资源")
+				c.Abort()
+				return
+			}
+		}
+
+		c.Next()
+	}
+}

+ 107 - 0
web-training/internal/model/user.go

@@ -0,0 +1,107 @@
+package model
+
+import (
+	"time"
+	"gorm.io/gorm"
+)
+
+// User 用户模型
+type User struct {
+	ID        uint           `gorm:"primaryKey" json:"id"`
+	Username  string         `gorm:"uniqueIndex;not null;size:50" json:"username"`
+	Email     string         `gorm:"uniqueIndex;not null;size:100" json:"email"`
+	Password  string         `gorm:"not null;size:255" json:"-"`
+	FirstName string         `gorm:"size:50" json:"first_name"`
+	LastName  string         `gorm:"size:50" json:"last_name"`
+	Avatar    string         `gorm:"size:255" json:"avatar"`
+	Phone     string         `gorm:"size:20" json:"phone"`
+	Address   string         `gorm:"size:255" json:"address"`
+	IsActive  bool           `gorm:"default:true" json:"is_active"`
+	Role      string         `gorm:"default:user;size:20" json:"role"`
+	CreatedAt time.Time      `json:"created_at"`
+	UpdatedAt time.Time      `json:"updated_at"`
+	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
+}
+
+// TableName 指定表名
+func (User) TableName() string {
+	return "users"
+}
+
+// BeforeCreate GORM钩子 - 创建前
+func (u *User) BeforeCreate(tx *gorm.DB) error {
+	// 这里可以添加密码加密等逻辑
+	return nil
+}
+
+// BeforeUpdate GORM钩子 - 更新前
+func (u *User) BeforeUpdate(tx *gorm.DB) error {
+	// 这里可以添加更新前的逻辑
+	return nil
+}
+
+// CreateUserRequest 创建用户请求
+type CreateUserRequest struct {
+	Username  string `json:"username" binding:"required,min=3,max=50"`
+	Email     string `json:"email" binding:"required,email"`
+	Password  string `json:"password" binding:"required,min=6"`
+	FirstName string `json:"first_name" binding:"max=50"`
+	LastName  string `json:"last_name" binding:"max=50"`
+	Phone     string `json:"phone" binding:"max=20"`
+	Address   string `json:"address" binding:"max=255"`
+}
+
+// UpdateUserRequest 更新用户请求
+type UpdateUserRequest struct {
+	FirstName string `json:"first_name" binding:"max=50"`
+	LastName  string `json:"last_name" binding:"max=50"`
+	Avatar    string `json:"avatar" binding:"max=255"`
+	Phone     string `json:"phone" binding:"max=20"`
+	Address   string `json:"address" binding:"max=255"`
+}
+
+// LoginRequest 登录请求
+type LoginRequest struct {
+	Username string `json:"username" binding:"required"`
+	Password string `json:"password" binding:"required"`
+}
+
+// UserResponse 用户响应
+type UserResponse struct {
+	ID        uint      `json:"id"`
+	Username  string    `json:"username"`
+	Email     string    `json:"email"`
+	FirstName string    `json:"first_name"`
+	LastName  string    `json:"last_name"`
+	Avatar    string    `json:"avatar"`
+	Phone     string    `json:"phone"`
+	Address   string    `json:"address"`
+	IsActive  bool      `json:"is_active"`
+	Role      string    `json:"role"`
+	CreatedAt time.Time `json:"created_at"`
+	UpdatedAt time.Time `json:"updated_at"`
+}
+
+// LoginResponse 登录响应
+type LoginResponse struct {
+	Token string       `json:"token"`
+	User  UserResponse `json:"user"`
+}
+
+// ToResponse 转换为响应格式
+func (u *User) ToResponse() UserResponse {
+	return UserResponse{
+		ID:        u.ID,
+		Username:  u.Username,
+		Email:     u.Email,
+		FirstName: u.FirstName,
+		LastName:  u.LastName,
+		Avatar:    u.Avatar,
+		Phone:     u.Phone,
+		Address:   u.Address,
+		IsActive:  u.IsActive,
+		Role:      u.Role,
+		CreatedAt: u.CreatedAt,
+		UpdatedAt: u.UpdatedAt,
+	}
+}

+ 106 - 0
web-training/internal/utils/response.go

@@ -0,0 +1,106 @@
+package utils
+
+import (
+	"net/http"
+	"github.com/gin-gonic/gin"
+)
+
+// APIResponse 统一API响应格式
+type APIResponse struct {
+	Code    int         `json:"code"`
+	Message string      `json:"message"`
+	Data    interface{} `json:"data,omitempty"`
+	Meta    *MetaInfo   `json:"meta,omitempty"`
+}
+
+// MetaInfo 分页信息
+type MetaInfo struct {
+	Page      int `json:"page"`
+	PageSize  int `json:"page_size"`
+	Total     int `json:"total"`
+	TotalPage int `json:"total_page"`
+}
+
+// SuccessResponse 成功响应
+func SuccessResponse(c *gin.Context, statusCode int, message string, data interface{}) {
+	response := APIResponse{
+		Code:    statusCode,
+		Message: message,
+		Data:    data,
+	}
+	c.JSON(statusCode, response)
+}
+
+// ErrorResponse 错误响应
+func ErrorResponse(c *gin.Context, statusCode int, message string, details string) {
+	response := APIResponse{
+		Code:    statusCode,
+		Message: message,
+		Data:    map[string]interface{}{"details": details},
+	}
+	c.JSON(statusCode, response)
+}
+
+// PaginatedResponse 分页响应
+func PaginatedResponse(c *gin.Context, statusCode int, message string, data interface{}, page, pageSize, total int) {
+	totalPage := (total + pageSize - 1) / pageSize
+	
+	response := APIResponse{
+		Code:    statusCode,
+		Message: message,
+		Data:    data,
+		Meta: &MetaInfo{
+			Page:      page,
+			PageSize:  pageSize,
+			Total:     total,
+			TotalPage: totalPage,
+		},
+	}
+	c.JSON(statusCode, response)
+}
+
+// GetPaginationParams 获取分页参数
+func GetPaginationParams(c *gin.Context) (page, pageSize int) {
+	page = 1
+	pageSize = 10
+
+	// 获取页码
+	if p := c.Query("page"); p != "" {
+		if parsedPage, err := parseInt(p); err == nil && parsedPage > 0 {
+			page = parsedPage
+		}
+	}
+
+	// 获取每页数量
+	if ps := c.Query("page_size"); ps != "" {
+		if parsedPageSize, err := parseInt(ps); err == nil && parsedPageSize > 0 && parsedPageSize <= 100 {
+			pageSize = parsedPageSize
+		}
+	}
+
+	return page, pageSize
+}
+
+// GetIDParam 获取ID参数
+func GetIDParam(c *gin.Context) (uint, error) {
+	idStr := c.Param("id")
+	id, err := parseUint(idStr)
+	if err != nil {
+		return 0, err
+	}
+	return id, nil
+}
+
+// parseInt 解析整数
+func parseInt(s string) (int, error) {
+	var result int
+	_, err := fmt.Sscanf(s, "%d", &result)
+	return result, err
+}
+
+// parseUint 解析无符号整数
+func parseUint(s string) (uint, error) {
+	var result uint
+	_, err := fmt.Sscanf(s, "%d", &result)
+	return result, err
+}

+ 104 - 0
web-training/pkg/auth/jwt.go

@@ -0,0 +1,104 @@
+package auth
+
+import (
+	"errors"
+	"time"
+	"github.com/golang-jwt/jwt/v5"
+)
+
+// JWTClaims JWT声明
+type JWTClaims struct {
+	UserID uint     `json:"user_id"`
+	Roles  []string `json:"roles"`
+	jwt.RegisteredClaims
+}
+
+// JWTService JWT服务
+type JWTService struct {
+	secretKey string
+	expire    int // 过期时间(秒)
+}
+
+// NewJWTService 创建JWT服务
+func NewJWTService(secretKey string, expire int) *JWTService {
+	return &JWTService{
+		secretKey: secretKey,
+		expire:    expire,
+	}
+}
+
+// GenerateToken 生成JWT令牌
+func (j *JWTService) GenerateToken(userID uint, roles []string) (string, error) {
+	// 创建声明
+	claims := JWTClaims{
+		UserID: userID,
+		Roles:  roles,
+		RegisteredClaims: jwt.RegisteredClaims{
+			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(j.expire) * time.Second)),
+			IssuedAt:  jwt.NewNumericDate(time.Now()),
+			NotBefore: jwt.NewNumericDate(time.Now()),
+			Issuer:    "web-training",
+			Subject:   "user-auth",
+		},
+	}
+
+	// 创建令牌
+	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+
+	// 签名令牌
+	tokenString, err := token.SignedString([]byte(j.secretKey))
+	if err != nil {
+		return "", err
+	}
+
+	return tokenString, nil
+}
+
+// ValidateToken 验证JWT令牌
+func (j *JWTService) ValidateToken(tokenString string) (*JWTClaims, error) {
+	// 解析令牌
+	token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
+		// 验证签名方法
+		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+			return nil, errors.New("unexpected signing method")
+		}
+		return []byte(j.secretKey), nil
+	})
+
+	if err != nil {
+		return nil, err
+	}
+
+	// 验证令牌有效性
+	if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
+		return claims, nil
+	}
+
+	return nil, errors.New("invalid token")
+}
+
+// RefreshToken 刷新JWT令牌
+func (j *JWTService) RefreshToken(tokenString string) (string, error) {
+	// 验证旧令牌
+	claims, err := j.ValidateToken(tokenString)
+	if err != nil {
+		return "", err
+	}
+
+	// 生成新令牌
+	return j.GenerateToken(claims.UserID, claims.Roles)
+}
+
+// ExtractTokenFromHeader 从请求头提取令牌
+func ExtractTokenFromHeader(authHeader string) (string, error) {
+	if authHeader == "" {
+		return "", errors.New("authorization header is empty")
+	}
+
+	parts := strings.Split(authHeader, " ")
+	if len(parts) != 2 || parts[0] != "Bearer" {
+		return "", errors.New("authorization header format must be Bearer {token}")
+	}
+
+	return parts[1], nil
+}

+ 124 - 0
web-training/scripts/init.sql

@@ -0,0 +1,124 @@
+-- 创建数据库表结构
+
+-- 用户表
+CREATE TABLE IF NOT EXISTS users (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    username VARCHAR(50) NOT NULL UNIQUE,
+    email VARCHAR(100) NOT NULL UNIQUE,
+    password VARCHAR(255) NOT NULL,
+    first_name VARCHAR(50),
+    last_name VARCHAR(50),
+    avatar VARCHAR(255),
+    phone VARCHAR(20),
+    address VARCHAR(255),
+    is_active BOOLEAN DEFAULT TRUE,
+    role VARCHAR(20) DEFAULT 'user',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    deleted_at TIMESTAMP NULL,
+    INDEX idx_username (username),
+    INDEX idx_email (email),
+    INDEX idx_deleted_at (deleted_at)
+);
+
+-- 商品分类表
+CREATE TABLE IF NOT EXISTS categories (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    name VARCHAR(100) NOT NULL,
+    description TEXT,
+    parent_id INT,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    FOREIGN KEY (parent_id) REFERENCES categories(id) ON DELETE SET NULL,
+    INDEX idx_parent_id (parent_id)
+);
+
+-- 商品表
+CREATE TABLE IF NOT EXISTS products (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    name VARCHAR(255) NOT NULL,
+    description TEXT,
+    price DECIMAL(10, 2) NOT NULL,
+    stock INT DEFAULT 0,
+    category_id INT,
+    image VARCHAR(255),
+    is_active BOOLEAN DEFAULT TRUE,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL,
+    INDEX idx_category_id (category_id),
+    INDEX idx_name (name),
+    INDEX idx_price (price)
+);
+
+-- 购物车表
+CREATE TABLE IF NOT EXISTS carts (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    user_id INT NOT NULL,
+    product_id INT NOT NULL,
+    quantity INT NOT NULL DEFAULT 1,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
+    FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE,
+    UNIQUE KEY unique_user_product (user_id, product_id),
+    INDEX idx_user_id (user_id),
+    INDEX idx_product_id (product_id)
+);
+
+-- 订单表
+CREATE TABLE IF NOT EXISTS orders (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    user_id INT NOT NULL,
+    order_number VARCHAR(50) NOT NULL UNIQUE,
+    total_amount DECIMAL(10, 2) NOT NULL,
+    status VARCHAR(20) DEFAULT 'pending',
+    shipping_address TEXT,
+    payment_method VARCHAR(50),
+    payment_status VARCHAR(20) DEFAULT 'pending',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
+    INDEX idx_user_id (user_id),
+    INDEX idx_order_number (order_number),
+    INDEX idx_status (status)
+);
+
+-- 订单项表
+CREATE TABLE IF NOT EXISTS order_items (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    order_id INT NOT NULL,
+    product_id INT NOT NULL,
+    quantity INT NOT NULL,
+    price DECIMAL(10, 2) NOT NULL,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
+    FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE,
+    INDEX idx_order_id (order_id),
+    INDEX idx_product_id (product_id)
+);
+
+-- 插入初始数据
+
+-- 插入默认管理员用户
+INSERT INTO users (username, email, password, first_name, last_name, role) VALUES 
+('admin', '[email protected]', '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'Admin', 'User', 'admin');
+
+-- 插入商品分类
+INSERT INTO categories (name, description) VALUES 
+('电子产品', '各类电子设备和配件'),
+('服装', '男女服装和配饰'),
+('家居', '家居用品和装饰'),
+('图书', '各类图书和教材'),
+('运动', '运动器材和服装');
+
+-- 插入示例商品
+INSERT INTO products (name, description, price, stock, category_id) VALUES 
+('智能手机', '最新款智能手机,配备高清摄像头和长续航电池', 2999.00, 100, 1),
+('笔记本电脑', '轻薄便携,高性能处理器,适合办公和娱乐', 5999.00, 50, 1),
+('运动T恤', '透气舒适,适合各种运动场景', 99.00, 200, 2),
+('牛仔裤', '经典款式,舒适耐穿', 199.00, 150, 2),
+('沙发', '现代简约风格,舒适耐用', 2999.00, 20, 3),
+('台灯', 'LED护眼台灯,多档调节', 199.00, 100, 3),
+('编程入门', '适合初学者的编程入门书籍', 59.00, 500, 4),
+('瑜伽垫', '防滑瑜伽垫,厚度适中', 99.00, 300, 5);

+ 275 - 0
web-training/web/static/css/style.css

@@ -0,0 +1,275 @@
+/* 全局样式 */
+body {
+    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+    line-height: 1.6;
+    color: #333;
+    background-color: #f8f9fa;
+}
+
+/* 导航栏样式 */
+.navbar-brand {
+    font-weight: bold;
+    font-size: 1.5rem;
+}
+
+.navbar-nav .nav-link {
+    font-weight: 500;
+    transition: color 0.3s ease;
+}
+
+.navbar-nav .nav-link:hover {
+    color: #007bff !important;
+}
+
+/* 卡片样式 */
+.card {
+    border: none;
+    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+    transition: transform 0.3s ease, box-shadow 0.3s ease;
+    margin-bottom: 20px;
+}
+
+.card:hover {
+    transform: translateY(-5px);
+    box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
+}
+
+.card-title {
+    color: #007bff;
+    font-weight: 600;
+}
+
+/* 按钮样式 */
+.btn {
+    border-radius: 50px;
+    padding: 8px 20px;
+    font-weight: 500;
+    transition: all 0.3s ease;
+}
+
+.btn-primary {
+    background-color: #007bff;
+    border-color: #007bff;
+}
+
+.btn-primary:hover {
+    background-color: #0069d9;
+    border-color: #0069d9;
+    transform: translateY(-2px);
+}
+
+.btn-outline-primary {
+    color: #007bff;
+    border-color: #007bff;
+}
+
+.btn-outline-primary:hover {
+    background-color: #007bff;
+    border-color: #007bff;
+    transform: translateY(-2px);
+}
+
+/* 表单样式 */
+.form-control {
+    border-radius: 10px;
+    border: 1px solid #ced4da;
+    padding: 10px 15px;
+    transition: border-color 0.3s ease, box-shadow 0.3s ease;
+}
+
+.form-control:focus {
+    border-color: #007bff;
+    box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
+}
+
+.form-label {
+    font-weight: 600;
+    color: #495057;
+}
+
+/* 商品卡片样式 */
+.product-card {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+}
+
+.product-card .card-img-top {
+    height: 200px;
+    object-fit: cover;
+    border-top-left-radius: 10px;
+    border-top-right-radius: 10px;
+}
+
+.product-card .card-body {
+    flex-grow: 1;
+    display: flex;
+    flex-direction: column;
+}
+
+.product-card .card-text {
+    flex-grow: 1;
+}
+
+.product-price {
+    font-size: 1.25rem;
+    font-weight: 700;
+    color: #dc3545;
+}
+
+/* 购物车样式 */
+.cart-item {
+    border-bottom: 1px solid #dee2e6;
+    padding: 15px 0;
+}
+
+.cart-item:last-child {
+    border-bottom: none;
+}
+
+.cart-item img {
+    width: 80px;
+    height: 80px;
+    object-fit: cover;
+    border-radius: 8px;
+}
+
+/* 订单状态样式 */
+.order-status {
+    padding: 5px 10px;
+    border-radius: 20px;
+    font-size: 0.875rem;
+    font-weight: 600;
+}
+
+.status-pending {
+    background-color: #ffc107;
+    color: #212529;
+}
+
+.status-processing {
+    background-color: #17a2b8;
+    color: white;
+}
+
+.status-shipped {
+    background-color: #6c757d;
+    color: white;
+}
+
+.status-delivered {
+    background-color: #28a745;
+    color: white;
+}
+
+.status-cancelled {
+    background-color: #dc3545;
+    color: white;
+}
+
+/* 分页样式 */
+.pagination .page-link {
+    border-radius: 50px;
+    margin: 0 3px;
+    color: #007bff;
+}
+
+.pagination .page-item.active .page-link {
+    background-color: #007bff;
+    border-color: #007bff;
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+    .jumbotron {
+        padding: 2rem !important;
+    }
+    
+    .display-4 {
+        font-size: 2.5rem;
+    }
+    
+    .card {
+        margin-bottom: 15px;
+    }
+}
+
+/* 加载动画 */
+.loading {
+    display: inline-block;
+    width: 20px;
+    height: 20px;
+    border: 3px solid rgba(0, 123, 255, 0.3);
+    border-radius: 50%;
+    border-top-color: #007bff;
+    animation: spin 1s ease-in-out infinite;
+}
+
+@keyframes spin {
+    to { transform: rotate(360deg); }
+}
+
+/* 提示消息样式 */
+.alert {
+    border-radius: 10px;
+    border: none;
+    padding: 15px 20px;
+}
+
+.alert-success {
+    background-color: rgba(40, 167, 69, 0.1);
+    color: #28a745;
+}
+
+.alert-danger {
+    background-color: rgba(220, 53, 69, 0.1);
+    color: #dc3545;
+}
+
+.alert-warning {
+    background-color: rgba(255, 193, 7, 0.1);
+    color: #ffc107;
+}
+
+.alert-info {
+    background-color: rgba(23, 162, 184, 0.1);
+    color: #17a2b8;
+}
+
+/* 表格样式 */
+.table {
+    border-radius: 10px;
+    overflow: hidden;
+    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+}
+
+.table thead th {
+    background-color: #007bff;
+    color: white;
+    border: none;
+}
+
+.table tbody tr:hover {
+    background-color: rgba(0, 123, 255, 0.05);
+}
+
+/* 模态框样式 */
+.modal-content {
+    border-radius: 15px;
+    border: none;
+    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
+}
+
+.modal-header {
+    border-bottom: 1px solid #dee2e6;
+    border-top-left-radius: 15px;
+    border-top-right-radius: 15px;
+    background-color: #f8f9fa;
+}
+
+.modal-footer {
+    border-top: 1px solid #dee2e6;
+    border-bottom-left-radius: 15px;
+    border-bottom-right-radius: 15px;
+    background-color: #f8f9fa;
+}

+ 315 - 0
web-training/web/static/js/main.js

@@ -0,0 +1,315 @@
+// 主要JavaScript功能
+
+// DOM加载完成后执行
+document.addEventListener('DOMContentLoaded', function() {
+    // 初始化工具提示
+    var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
+    var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
+        return new bootstrap.Tooltip(tooltipTriggerEl);
+    });
+
+    // 初始化弹出框
+    var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
+    var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
+        return new bootstrap.Popover(popoverTriggerEl);
+    });
+});
+
+// API请求封装
+const API = {
+    // 基础URL
+    baseURL: '/api/v1',
+
+    // 获取认证令牌
+    getAuthToken: function() {
+        return localStorage.getItem('authToken');
+    },
+
+    // 设置认证令牌
+    setAuthToken: function(token) {
+        localStorage.setItem('authToken', token);
+    },
+
+    // 清除认证令牌
+    clearAuthToken: function() {
+        localStorage.removeItem('authToken');
+    },
+
+    // 通用请求方法
+    request: function(method, url, data = null) {
+        const options = {
+            method: method,
+            headers: {
+                'Content-Type': 'application/json',
+            },
+        };
+
+        // 添加认证头
+        const token = this.getAuthToken();
+        if (token) {
+            options.headers['Authorization'] = `Bearer ${token}`;
+        }
+
+        // 添加请求体
+        if (data) {
+            options.body = JSON.stringify(data);
+        }
+
+        return fetch(this.baseURL + url, options)
+            .then(response => {
+                if (!response.ok) {
+                    throw new Error(`HTTP error! status: ${response.status}`);
+                }
+                return response.json();
+            });
+    },
+
+    // GET请求
+    get: function(url) {
+        return this.request('GET', url);
+    },
+
+    // POST请求
+    post: function(url, data) {
+        return this.request('POST', url, data);
+    },
+
+    // PUT请求
+    put: function(url, data) {
+        return this.request('PUT', url, data);
+    },
+
+    // DELETE请求
+    delete: function(url) {
+        return this.request('DELETE', url);
+    }
+};
+
+// 用户认证相关功能
+const Auth = {
+    // 登录
+    login: function(username, password) {
+        return API.post('/login', { username, password })
+            .then(response => {
+                if (response.code === 200) {
+                    API.setAuthToken(response.data.token);
+                    localStorage.setItem('user', JSON.stringify(response.data.user));
+                    return response.data;
+                } else {
+                    throw new Error(response.message);
+                }
+            });
+    },
+
+    // 注册
+    register: function(userData) {
+        return API.post('/register', userData)
+            .then(response => {
+                if (response.code === 201) {
+                    return response.data;
+                } else {
+                    throw new Error(response.message);
+                }
+            });
+    },
+
+    // 登出
+    logout: function() {
+        API.clearAuthToken();
+        localStorage.removeItem('user');
+        window.location.href = '/login';
+    },
+
+    // 获取当前用户
+    getCurrentUser: function() {
+        const userStr = localStorage.getItem('user');
+        return userStr ? JSON.parse(userStr) : null;
+    },
+
+    // 检查是否已登录
+    isLoggedIn: function() {
+        return !!API.getAuthToken();
+    }
+};
+
+// 商品相关功能
+const Products = {
+    // 获取商品列表
+    getList: function(page = 1, pageSize = 10, search = '') {
+        let url = `/products?page=${page}&page_size=${pageSize}`;
+        if (search) {
+            url += `&search=${search}`;
+        }
+        return API.get(url);
+    },
+
+    // 获取商品详情
+    getDetail: function(id) {
+        return API.get(`/products/${id}`);
+    },
+
+    // 创建商品
+    create: function(productData) {
+        return API.post('/products', productData);
+    },
+
+    // 更新商品
+    update: function(id, productData) {
+        return API.put(`/products/${id}`, productData);
+    },
+
+    // 删除商品
+    delete: function(id) {
+        return API.delete(`/products/${id}`);
+    }
+};
+
+// 购物车相关功能
+const Cart = {
+    // 获取购物车内容
+    getItems: function() {
+        return API.get('/cart');
+    },
+
+    // 添加商品到购物车
+    addItem: function(productId, quantity = 1) {
+        return API.post('/cart/items', { product_id: productId, quantity });
+    },
+
+    // 更新购物车商品数量
+    updateItem: function(itemId, quantity) {
+        return API.put(`/cart/items/${itemId}`, { quantity });
+    },
+
+    // 删除购物车商品
+    removeItem: function(itemId) {
+        return API.delete(`/cart/items/${itemId}`);
+    },
+
+    // 清空购物车
+    clear: function() {
+        return API.delete('/cart');
+    }
+};
+
+// 订单相关功能
+const Orders = {
+    // 获取订单列表
+    getList: function(page = 1, pageSize = 10) {
+        return API.get(`/orders?page=${page}&page_size=${pageSize}`);
+    },
+
+    // 获取订单详情
+    getDetail: function(id) {
+        return API.get(`/orders/${id}`);
+    },
+
+    // 创建订单
+    create: function(orderData) {
+        return API.post('/orders', orderData);
+    },
+
+    // 更新订单状态
+    updateStatus: function(id, status) {
+        return API.put(`/orders/${id}`, { status });
+    }
+};
+
+// 工具函数
+const Utils = {
+    // 显示提示消息
+    showAlert: function(message, type = 'info') {
+        const alertDiv = document.createElement('div');
+        alertDiv.className = `alert alert-${type} alert-dismissible fade show`;
+        alertDiv.innerHTML = `
+            ${message}
+            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
+        `;
+        
+        const container = document.querySelector('.container');
+        container.insertBefore(alertDiv, container.firstChild);
+        
+        // 5秒后自动关闭
+        setTimeout(() => {
+            alertDiv.remove();
+        }, 5000);
+    },
+
+    // 格式化价格
+    formatPrice: function(price) {
+        return `¥${parseFloat(price).toFixed(2)}`;
+    },
+
+    // 格式化日期
+    formatDate: function(dateString) {
+        const date = new Date(dateString);
+        return date.toLocaleDateString('zh-CN', {
+            year: 'numeric',
+            month: 'long',
+            day: 'numeric',
+            hour: '2-digit',
+            minute: '2-digit'
+        });
+    },
+
+    // 显示加载状态
+    showLoading: function(element) {
+        element.innerHTML = '<span class="loading"></span> 加载中...';
+        element.disabled = true;
+    },
+
+    // 隐藏加载状态
+    hideLoading: function(element, originalText) {
+        element.innerHTML = originalText;
+        element.disabled = false;
+    },
+
+    // 确认对话框
+    confirm: function(message, callback) {
+        if (confirm(message)) {
+            callback();
+        }
+    }
+};
+
+// 页面初始化
+document.addEventListener('DOMContentLoaded', function() {
+    // 检查登录状态
+    if (Auth.isLoggedIn()) {
+        const user = Auth.getCurrentUser();
+        // 更新导航栏显示用户信息
+        const navbar = document.querySelector('.navbar-nav');
+        if (navbar) {
+            // 隐藏登录/注册链接
+            const loginLink = navbar.querySelector('a[href="/login"]');
+            const registerLink = navbar.querySelector('a[href="/register"]');
+            
+            if (loginLink) loginLink.style.display = 'none';
+            if (registerLink) registerLink.style.display = 'none';
+            
+            // 添加用户信息
+            const userItem = document.createElement('li');
+            userItem.className = 'nav-item dropdown';
+            userItem.innerHTML = `
+                <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
+                    ${user.username}
+                </a>
+                <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
+                    <li><a class="dropdown-item" href="/profile">个人信息</a></li>
+                    <li><a class="dropdown-item" href="/orders">我的订单</a></li>
+                    <li><hr class="dropdown-divider"></li>
+                    <li><a class="dropdown-item" href="#" onclick="Auth.logout()">退出登录</a></li>
+                </ul>
+            `;
+            navbar.appendChild(userItem);
+        }
+    }
+});
+
+// 导出对象供其他脚本使用
+window.API = API;
+window.Auth = Auth;
+window.Products = Products;
+window.Cart = Cart;
+window.Orders = Orders;
+window.Utils = Utils;

+ 135 - 0
web-training/web/templates/index.html

@@ -0,0 +1,135 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>{{.title}}</title>
+    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
+    <link rel="stylesheet" href="/static/css/style.css">
+</head>
+<body>
+    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
+        <div class="container">
+            <a class="navbar-brand" href="/">Go Web Training</a>
+            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
+                <span class="navbar-toggler-icon"></span>
+            </button>
+            <div class="collapse navbar-collapse" id="navbarNav">
+                <ul class="navbar-nav me-auto">
+                    <li class="nav-item">
+                        <a class="nav-link active" href="/">首页</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/products">商品</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/cart">购物车</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/orders">订单</a>
+                    </li>
+                </ul>
+                <ul class="navbar-nav">
+                    <li class="nav-item">
+                        <a class="nav-link" href="/login">登录</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/register">注册</a>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </nav>
+
+    <main class="container mt-4">
+        <div class="row">
+            <div class="col-md-12">
+                <div class="jumbotron bg-light p-5 rounded">
+                    <h1 class="display-4">欢迎来到Go Web训练项目</h1>
+                    <p class="lead">这是一个基于Go语言的Web开发训练项目,包含用户管理、商品管理、购物车和订单系统等功能。</p>
+                    <hr class="my-4">
+                    <p>点击下方按钮开始探索项目功能。</p>
+                    <a class="btn btn-primary btn-lg" href="/products" role="button">浏览商品</a>
+                </div>
+            </div>
+        </div>
+
+        <div class="row mt-5">
+            <div class="col-md-4">
+                <div class="card">
+                    <div class="card-body">
+                        <h5 class="card-title">用户管理</h5>
+                        <p class="card-text">完整的用户注册、登录、个人信息管理功能,支持JWT认证和权限控制。</p>
+                        <a href="/register" class="btn btn-outline-primary">立即注册</a>
+                    </div>
+                </div>
+            </div>
+            <div class="col-md-4">
+                <div class="card">
+                    <div class="card-body">
+                        <h5 class="card-title">商品管理</h5>
+                        <p class="card-text">商品展示、分类管理、搜索功能,支持图片上传和库存管理。</p>
+                        <a href="/products" class="btn btn-outline-primary">查看商品</a>
+                    </div>
+                </div>
+            </div>
+            <div class="col-md-4">
+                <div class="card">
+                    <div class="card-body">
+                        <h5 class="card-title">订单系统</h5>
+                        <p class="card-text">完整的购物车和订单流程,支持多种支付方式和订单状态跟踪。</p>
+                        <a href="/cart" class="btn btn-outline-primary">购物车</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div class="row mt-5">
+            <div class="col-md-12">
+                <h2>技术特性</h2>
+                <div class="row">
+                    <div class="col-md-6">
+                        <h4>后端技术</h4>
+                        <ul>
+                            <li>Go语言 + Gin框架</li>
+                            <li>MySQL数据库 + GORM ORM</li>
+                            <li>Redis缓存</li>
+                            <li>JWT认证</li>
+                            <li>RESTful API设计</li>
+                            <li>WebSocket实时通信</li>
+                        </ul>
+                    </div>
+                    <div class="col-md-6">
+                        <h4>开发特性</h4>
+                        <ul>
+                            <li>前后端分离架构</li>
+                            <li>Docker容器化部署</li>
+                            <li>统一错误处理</li>
+                            <li>请求限流和安全防护</li>
+                            <li>完整的测试覆盖</li>
+                            <li>API文档自动生成</li>
+                        </ul>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </main>
+
+    <footer class="bg-dark text-light mt-5 py-4">
+        <div class="container">
+            <div class="row">
+                <div class="col-md-6">
+                    <h5>Go Web Training</h5>
+                    <p>一个全面的Go语言Web开发学习项目</p>
+                </div>
+                <div class="col-md-6 text-end">
+                    <p>&copy; 2023 Go Web Training. All rights reserved.</p>
+                </div>
+            </div>
+        </div>
+    </footer>
+
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
+    <script src="/static/js/main.js"></script>
+</body>
+</html>