重构项目结构:迁移到单体架构并优化代码组织
- 删除分布式架构相关文件和配置 - 将backend-distributed重命名为backend保留分布式代码作为参考 - 优化backend-single单体架构实现 - 添加Coze API集成相关文档和测试 - 清理项目根目录的部署脚本和配置文件 - 更新WebSocket和消息服务实现 - 完善认证服务和密码加密功能
This commit is contained in:
@@ -1,285 +0,0 @@
|
||||
# 情绪博物馆Spring Cloud Alibaba微服务架构设计
|
||||
|
||||
**版本**: v1.0
|
||||
**创建时间**: 2025-07-12
|
||||
**技术栈**: Spring Cloud Alibaba 2022.0.0.0
|
||||
**Spring Boot版本**: 3.0.2
|
||||
**JDK版本**: 17+
|
||||
|
||||
---
|
||||
|
||||
## 📋 架构分析
|
||||
|
||||
### 业务模块分析
|
||||
基于功能需求文档分析,情绪博物馆包含以下核心业务模块:
|
||||
|
||||
1. **用户认证模块** - 账号、密码、手机号登录
|
||||
2. **AI对话模块** - 智能对话、情绪分析
|
||||
3. **情绪记录模块** - 情绪日历、记录管理
|
||||
4. **成长课题模块** - 课题系统、互动记录
|
||||
5. **地图探索模块** - 地点标记、社区分享
|
||||
6. **成就奖励模块** - 成就系统、积分奖励
|
||||
7. **用户统计模块** - 数据统计、分析报告
|
||||
|
||||
### 技术架构选型
|
||||
|
||||
#### Spring Cloud Alibaba 2022.0.0.0 组件
|
||||
- **Nacos**: 服务注册发现 + 配置中心
|
||||
- **Sentinel**: 流量控制、熔断降级
|
||||
- **Seata**: 分布式事务
|
||||
- **Gateway**: API网关
|
||||
- **OpenFeign**: 服务间调用
|
||||
- **Dubbo**: RPC通信(可选)
|
||||
|
||||
#### 基础设施组件
|
||||
- **MySQL 8.0**: 主数据库
|
||||
- **Redis 7.0**: 缓存 + 分布式锁
|
||||
- **RocketMQ**: 消息队列
|
||||
- **Elasticsearch**: 搜索引擎
|
||||
- **MinIO**: 对象存储
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 微服务架构设计
|
||||
|
||||
### 服务拆分策略
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A[API Gateway] --> B[用户服务]
|
||||
A --> C[AI对话服务]
|
||||
A --> D[情绪记录服务]
|
||||
A --> E[成长课题服务]
|
||||
A --> F[地图探索服务]
|
||||
A --> G[成就奖励服务]
|
||||
A --> H[统计分析服务]
|
||||
|
||||
B --> I[MySQL-用户库]
|
||||
C --> J[MySQL-对话库]
|
||||
D --> K[MySQL-情绪库]
|
||||
E --> L[MySQL-成长库]
|
||||
F --> M[MySQL-地图库]
|
||||
G --> N[MySQL-奖励库]
|
||||
H --> O[MySQL-统计库]
|
||||
|
||||
P[Nacos] --> A
|
||||
P --> B
|
||||
P --> C
|
||||
P --> D
|
||||
P --> E
|
||||
P --> F
|
||||
P --> G
|
||||
P --> H
|
||||
|
||||
Q[Redis] --> B
|
||||
Q --> C
|
||||
Q --> D
|
||||
Q --> E
|
||||
Q --> F
|
||||
Q --> G
|
||||
Q --> H
|
||||
```
|
||||
|
||||
### 微服务清单
|
||||
|
||||
| 服务名称 | 端口 | 职责 | 数据库 |
|
||||
|---------|------|------|--------|
|
||||
| emotion-gateway | 8080 | API网关、路由、鉴权 | - |
|
||||
| emotion-user | 8081 | 用户认证、资料管理 | user, user_stats |
|
||||
| emotion-ai | 8082 | AI对话、情绪分析 | conversation, message |
|
||||
| emotion-record | 8083 | 情绪记录、日历管理 | emotion_record |
|
||||
| emotion-growth | 8084 | 成长课题、互动记录 | growth_topic, topic_interaction |
|
||||
| emotion-explore | 8085 | 地图探索、社区分享 | location_pin, community_post, comment |
|
||||
| emotion-reward | 8086 | 成就奖励、积分管理 | achievement, reward |
|
||||
| emotion-stats | 8087 | 数据统计、分析报告 | 跨库查询 |
|
||||
|
||||
---
|
||||
|
||||
## 📦 技术版本选择
|
||||
|
||||
### Spring Cloud Alibaba 2022.0.0.0
|
||||
这是当前最稳定的版本,具有以下优势:
|
||||
- ✅ 与Spring Boot 3.0.x完美兼容
|
||||
- ✅ 支持JDK 17+
|
||||
- ✅ 生产环境验证充分
|
||||
- ✅ 社区活跃,文档完善
|
||||
- ✅ 阿里云原生支持
|
||||
|
||||
### 版本依赖关系
|
||||
```xml
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<spring-boot.version>3.0.2</spring-boot.version>
|
||||
<spring-cloud.version>2022.0.0</spring-cloud.version>
|
||||
<spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version>
|
||||
<mysql.version>8.0.33</mysql.version>
|
||||
<redis.version>7.0.8</redis.version>
|
||||
<mybatis-plus.version>3.5.3.1</mybatis-plus.version>
|
||||
</properties>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 核心配置设计
|
||||
|
||||
### Nacos配置中心
|
||||
```yaml
|
||||
# application-dev.yml
|
||||
spring:
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: localhost:8848
|
||||
namespace: emotion-dev
|
||||
group: DEFAULT_GROUP
|
||||
config:
|
||||
server-addr: localhost:8848
|
||||
namespace: emotion-dev
|
||||
group: DEFAULT_GROUP
|
||||
file-extension: yml
|
||||
shared-configs:
|
||||
- data-id: common-mysql.yml
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
- data-id: common-redis.yml
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
```
|
||||
|
||||
### 数据库配置
|
||||
```yaml
|
||||
# common-mysql.yml
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://localhost:3306/emotion_museum?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
||||
username: ${DB_USERNAME:root}
|
||||
password: ${DB_PASSWORD:123456}
|
||||
hikari:
|
||||
minimum-idle: 5
|
||||
maximum-pool-size: 20
|
||||
idle-timeout: 600000
|
||||
max-lifetime: 1800000
|
||||
connection-timeout: 30000
|
||||
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: assign_uuid
|
||||
logic-delete-field: deleted
|
||||
logic-delete-value: 1
|
||||
logic-not-delete-value: 0
|
||||
```
|
||||
|
||||
### Redis配置
|
||||
```yaml
|
||||
# common-redis.yml
|
||||
spring:
|
||||
data:
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
password: ${REDIS_PASSWORD:}
|
||||
database: 0
|
||||
timeout: 3000ms
|
||||
lettuce:
|
||||
pool:
|
||||
max-active: 20
|
||||
max-idle: 10
|
||||
min-idle: 5
|
||||
max-wait: 3000ms
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 实施计划
|
||||
|
||||
### Phase 1: 基础设施搭建 (1周)
|
||||
1. **父工程创建**
|
||||
- Maven多模块项目结构
|
||||
- 版本依赖管理
|
||||
- 公共组件抽取
|
||||
|
||||
2. **注册中心部署**
|
||||
- Nacos Server安装配置
|
||||
- 命名空间和分组设置
|
||||
- 配置文件管理
|
||||
|
||||
3. **数据库初始化**
|
||||
- MySQL数据库创建
|
||||
- 表结构和索引创建
|
||||
- 初始数据导入
|
||||
|
||||
### Phase 2: 核心服务开发 (2-3周)
|
||||
1. **网关服务** (emotion-gateway)
|
||||
- 路由配置
|
||||
- 统一鉴权
|
||||
- 限流熔断
|
||||
|
||||
2. **用户服务** (emotion-user)
|
||||
- 用户注册登录
|
||||
- JWT Token管理
|
||||
- 用户资料CRUD
|
||||
|
||||
3. **AI对话服务** (emotion-ai)
|
||||
- 对话管理
|
||||
- 消息处理
|
||||
- AI接口集成
|
||||
|
||||
### Phase 3: 业务服务开发 (3-4周)
|
||||
1. **情绪记录服务** (emotion-record)
|
||||
2. **成长课题服务** (emotion-growth)
|
||||
3. **地图探索服务** (emotion-explore)
|
||||
4. **成就奖励服务** (emotion-reward)
|
||||
|
||||
### Phase 4: 数据服务开发 (1-2周)
|
||||
1. **统计分析服务** (emotion-stats)
|
||||
2. **监控告警配置**
|
||||
3. **性能优化调试**
|
||||
|
||||
---
|
||||
|
||||
## 📊 服务间通信设计
|
||||
|
||||
### API调用关系
|
||||
```
|
||||
emotion-gateway
|
||||
├── emotion-user (用户认证)
|
||||
├── emotion-ai (AI对话)
|
||||
│ └── emotion-user (用户信息)
|
||||
├── emotion-record (情绪记录)
|
||||
│ └── emotion-user (用户验证)
|
||||
├── emotion-growth (成长课题)
|
||||
│ ├── emotion-user (用户信息)
|
||||
│ └── emotion-reward (奖励发放)
|
||||
├── emotion-explore (地图探索)
|
||||
│ └── emotion-user (用户信息)
|
||||
├── emotion-reward (成就奖励)
|
||||
│ └── emotion-user (用户信息)
|
||||
└── emotion-stats (统计分析)
|
||||
├── emotion-user (用户数据)
|
||||
├── emotion-ai (对话数据)
|
||||
├── emotion-record (情绪数据)
|
||||
├── emotion-growth (成长数据)
|
||||
└── emotion-explore (探索数据)
|
||||
```
|
||||
|
||||
### 消息队列设计
|
||||
```yaml
|
||||
# RocketMQ Topic设计
|
||||
topics:
|
||||
- emotion-user-events # 用户事件
|
||||
- emotion-conversation # 对话事件
|
||||
- emotion-record-events # 情绪记录事件
|
||||
- emotion-growth-events # 成长事件
|
||||
- emotion-explore-events # 探索事件
|
||||
- emotion-reward-events # 奖励事件
|
||||
- emotion-stats-events # 统计事件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*接下来将按照此架构设计逐步创建各个微服务模块*
|
||||
@@ -1,610 +0,0 @@
|
||||
# 情绪博物馆技术架构完善建议
|
||||
|
||||
**文档版本**: v1.0
|
||||
**创建时间**: 2025-07-12
|
||||
**基于**: 现有代码架构分析
|
||||
|
||||
---
|
||||
|
||||
## 📋 目录
|
||||
|
||||
- [1. 当前架构分析](#1-当前架构分析)
|
||||
- [2. 架构完善建议](#2-架构完善建议)
|
||||
- [3. 具体实施方案](#3-具体实施方案)
|
||||
- [4. 性能优化建议](#4-性能优化建议)
|
||||
- [5. 安全性增强](#5-安全性增强)
|
||||
- [6. 可维护性提升](#6-可维护性提升)
|
||||
|
||||
---
|
||||
|
||||
## 1. 当前架构分析
|
||||
|
||||
### 1.1 架构优势 ✅
|
||||
|
||||
#### 清晰的分层结构
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ SwiftUI Views │ ← 表现层
|
||||
├─────────────────────────────────────┤
|
||||
│ ViewModel/Manager │ ← 业务逻辑层
|
||||
├─────────────────────────────────────┤
|
||||
│ Services │ ← 服务层
|
||||
├─────────────────────────────────────┤
|
||||
│ Models │ ← 数据模型层
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 良好的状态管理
|
||||
- ✅ 使用 `@ObservableObject` 进行状态管理
|
||||
- ✅ `NavigationManager` 统一管理导航状态
|
||||
- ✅ `ThemeManager` 管理主题切换
|
||||
- ✅ `MockDataManager` 提供数据服务
|
||||
|
||||
#### 模块化设计
|
||||
- ✅ 清晰的文件组织结构
|
||||
- ✅ 功能模块相对独立
|
||||
- ✅ 可复用的UI组件
|
||||
|
||||
### 1.2 架构不足 ❌
|
||||
|
||||
#### 数据持久化缺失
|
||||
- ❌ 缺少真实的数据存储层
|
||||
- ❌ 依赖模拟数据,无法持久化用户数据
|
||||
- ❌ 没有数据同步机制
|
||||
|
||||
#### 服务层不完整
|
||||
- ❌ AI服务只有接口定义,缺少实现
|
||||
- ❌ 缺少网络服务层
|
||||
- ❌ 缺少错误处理机制
|
||||
|
||||
#### 依赖注入不规范
|
||||
- ❌ 大量使用 `shared` 单例模式
|
||||
- ❌ 组件间耦合度较高
|
||||
- ❌ 测试困难
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构完善建议
|
||||
|
||||
### 2.1 引入依赖注入容器
|
||||
|
||||
#### 创建DI容器
|
||||
```swift
|
||||
// DIContainer.swift
|
||||
class DIContainer: ObservableObject {
|
||||
static let shared = DIContainer()
|
||||
|
||||
private var services: [String: Any] = [:]
|
||||
|
||||
func register<T>(_ type: T.Type, instance: T) {
|
||||
let key = String(describing: type)
|
||||
services[key] = instance
|
||||
}
|
||||
|
||||
func resolve<T>(_ type: T.Type) -> T {
|
||||
let key = String(describing: type)
|
||||
guard let service = services[key] as? T else {
|
||||
fatalError("Service \(key) not registered")
|
||||
}
|
||||
return service
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 服务注册
|
||||
```swift
|
||||
// ServiceRegistration.swift
|
||||
extension DIContainer {
|
||||
func registerServices() {
|
||||
// 数据服务
|
||||
register(DataServiceProtocol.self, instance: CoreDataService())
|
||||
|
||||
// AI服务
|
||||
register(AIServiceProtocol.self, instance: OpenAIService())
|
||||
|
||||
// 位置服务
|
||||
register(LocationServiceProtocol.self, instance: LocationService())
|
||||
|
||||
// 网络服务
|
||||
register(NetworkServiceProtocol.self, instance: NetworkService())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 完善服务层架构
|
||||
|
||||
#### 网络服务层
|
||||
```swift
|
||||
// NetworkService.swift
|
||||
protocol NetworkServiceProtocol {
|
||||
func request<T: Codable>(_ endpoint: APIEndpoint) async throws -> T
|
||||
func upload(data: Data, to endpoint: APIEndpoint) async throws -> UploadResponse
|
||||
}
|
||||
|
||||
class NetworkService: NetworkServiceProtocol {
|
||||
private let session: URLSession
|
||||
private let baseURL: URL
|
||||
|
||||
init(session: URLSession = .shared, baseURL: URL) {
|
||||
self.session = session
|
||||
self.baseURL = baseURL
|
||||
}
|
||||
|
||||
func request<T: Codable>(_ endpoint: APIEndpoint) async throws -> T {
|
||||
let request = try buildRequest(for: endpoint)
|
||||
let (data, response) = try await session.data(for: request)
|
||||
|
||||
guard let httpResponse = response as? HTTPURLResponse,
|
||||
200...299 ~= httpResponse.statusCode else {
|
||||
throw NetworkError.invalidResponse
|
||||
}
|
||||
|
||||
return try JSONDecoder().decode(T.self, from: data)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 数据服务层
|
||||
```swift
|
||||
// DataService.swift
|
||||
protocol DataServiceProtocol {
|
||||
func save<T: Codable>(_ object: T) async throws
|
||||
func fetch<T: Codable>(_ type: T.Type, predicate: NSPredicate?) async throws -> [T]
|
||||
func delete<T: Codable>(_ object: T) async throws
|
||||
}
|
||||
|
||||
class CoreDataService: DataServiceProtocol {
|
||||
private let container: NSPersistentContainer
|
||||
|
||||
init() {
|
||||
container = NSPersistentContainer(name: "EmotionMuseum")
|
||||
container.loadPersistentStores { _, error in
|
||||
if let error = error {
|
||||
fatalError("Core Data error: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func save<T: Codable>(_ object: T) async throws {
|
||||
let context = container.viewContext
|
||||
// 实现保存逻辑
|
||||
try context.save()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 引入Repository模式
|
||||
|
||||
#### 数据仓库接口
|
||||
```swift
|
||||
// Repository.swift
|
||||
protocol Repository {
|
||||
associatedtype Entity
|
||||
|
||||
func create(_ entity: Entity) async throws
|
||||
func read(id: UUID) async throws -> Entity?
|
||||
func update(_ entity: Entity) async throws
|
||||
func delete(id: UUID) async throws
|
||||
func list(predicate: NSPredicate?) async throws -> [Entity]
|
||||
}
|
||||
|
||||
// 具体实现
|
||||
class ConversationRepository: Repository {
|
||||
typealias Entity = Conversation
|
||||
|
||||
private let dataService: DataServiceProtocol
|
||||
|
||||
init(dataService: DataServiceProtocol) {
|
||||
self.dataService = dataService
|
||||
}
|
||||
|
||||
func create(_ conversation: Conversation) async throws {
|
||||
try await dataService.save(conversation)
|
||||
}
|
||||
|
||||
func list(predicate: NSPredicate? = nil) async throws -> [Conversation] {
|
||||
return try await dataService.fetch(Conversation.self, predicate: predicate)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 改进ViewModel架构
|
||||
|
||||
#### 基础ViewModel
|
||||
```swift
|
||||
// BaseViewModel.swift
|
||||
@MainActor
|
||||
class BaseViewModel: ObservableObject {
|
||||
@Published var isLoading = false
|
||||
@Published var error: AppError?
|
||||
|
||||
protected func withLoading<T>(_ operation: () async throws -> T) async rethrows -> T {
|
||||
isLoading = true
|
||||
defer { isLoading = false }
|
||||
return try await operation()
|
||||
}
|
||||
|
||||
protected func handleError(_ error: Error) {
|
||||
self.error = AppError(from: error)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 具体ViewModel实现
|
||||
```swift
|
||||
// ConversationViewModel.swift
|
||||
@MainActor
|
||||
class ConversationViewModel: BaseViewModel {
|
||||
@Published var conversations: [Conversation] = []
|
||||
@Published var currentConversation: Conversation?
|
||||
|
||||
private let repository: ConversationRepository
|
||||
private let aiService: AIServiceProtocol
|
||||
|
||||
init(repository: ConversationRepository, aiService: AIServiceProtocol) {
|
||||
self.repository = repository
|
||||
self.aiService = aiService
|
||||
super.init()
|
||||
}
|
||||
|
||||
func loadConversations() async {
|
||||
await withLoading {
|
||||
do {
|
||||
conversations = try await repository.list()
|
||||
} catch {
|
||||
handleError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sendMessage(_ content: String) async {
|
||||
guard let conversation = currentConversation else { return }
|
||||
|
||||
do {
|
||||
// 添加用户消息
|
||||
let userMessage = Message(
|
||||
conversationId: conversation.id,
|
||||
content: content,
|
||||
type: .text,
|
||||
sender: .user
|
||||
)
|
||||
|
||||
// 获取AI回复
|
||||
let aiResponse = try await aiService.sendMessage(content)
|
||||
let aiMessage = Message(
|
||||
conversationId: conversation.id,
|
||||
content: aiResponse.content,
|
||||
type: .text,
|
||||
sender: .ai
|
||||
)
|
||||
|
||||
// 更新对话
|
||||
var updatedConversation = conversation
|
||||
updatedConversation.messages.append(contentsOf: [userMessage, aiMessage])
|
||||
|
||||
try await repository.update(updatedConversation)
|
||||
currentConversation = updatedConversation
|
||||
|
||||
} catch {
|
||||
handleError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 具体实施方案
|
||||
|
||||
### 3.1 阶段性重构计划
|
||||
|
||||
#### Phase 1: 基础设施搭建 (1周)
|
||||
1. **创建DI容器**
|
||||
- 实现依赖注入容器
|
||||
- 注册核心服务
|
||||
- 更新App启动流程
|
||||
|
||||
2. **完善错误处理**
|
||||
- 定义统一错误类型
|
||||
- 实现错误处理机制
|
||||
- 添加用户友好的错误提示
|
||||
|
||||
3. **网络服务层**
|
||||
- 实现基础网络服务
|
||||
- 添加请求/响应拦截器
|
||||
- 实现重试机制
|
||||
|
||||
#### Phase 2: 数据层重构 (1-2周)
|
||||
1. **Core Data集成**
|
||||
- 设计数据模型
|
||||
- 实现数据服务
|
||||
- 数据迁移策略
|
||||
|
||||
2. **Repository模式**
|
||||
- 实现各个Repository
|
||||
- 数据缓存策略
|
||||
- 离线数据支持
|
||||
|
||||
#### Phase 3: 业务层重构 (1-2周)
|
||||
1. **ViewModel重构**
|
||||
- 重构现有ViewModel
|
||||
- 添加单元测试
|
||||
- 优化状态管理
|
||||
|
||||
2. **服务集成**
|
||||
- AI服务真实实现
|
||||
- 地图服务集成
|
||||
- 推送服务集成
|
||||
|
||||
### 3.2 代码重构示例
|
||||
|
||||
#### 重构前 (现状)
|
||||
```swift
|
||||
// RecordView.swift - 现状
|
||||
struct RecordView: View {
|
||||
@EnvironmentObject var mockData: MockDataManager
|
||||
@EnvironmentObject var navigationManager: NavigationManager
|
||||
|
||||
var body: some View {
|
||||
// 直接使用mockData
|
||||
// 紧耦合,难以测试
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 重构后 (建议)
|
||||
```swift
|
||||
// RecordView.swift - 重构后
|
||||
struct RecordView: View {
|
||||
@StateObject private var viewModel: RecordViewModel
|
||||
|
||||
init(viewModel: RecordViewModel = DIContainer.shared.resolve(RecordViewModel.self)) {
|
||||
self._viewModel = StateObject(wrappedValue: viewModel)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
// 使用viewModel
|
||||
// 松耦合,易于测试
|
||||
}
|
||||
}
|
||||
|
||||
// RecordViewModel.swift
|
||||
@MainActor
|
||||
class RecordViewModel: BaseViewModel {
|
||||
@Published var conversations: [Conversation] = []
|
||||
@Published var currentMessage: String = ""
|
||||
|
||||
private let conversationRepository: ConversationRepository
|
||||
private let aiService: AIServiceProtocol
|
||||
|
||||
init(conversationRepository: ConversationRepository, aiService: AIServiceProtocol) {
|
||||
self.conversationRepository = conversationRepository
|
||||
self.aiService = aiService
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 性能优化建议
|
||||
|
||||
### 4.1 内存管理优化
|
||||
|
||||
#### 图片缓存策略
|
||||
```swift
|
||||
// ImageCache.swift
|
||||
class ImageCache {
|
||||
static let shared = ImageCache()
|
||||
private let cache = NSCache<NSString, UIImage>()
|
||||
private let fileManager = FileManager.default
|
||||
|
||||
func image(for url: String) async -> UIImage? {
|
||||
// 内存缓存 -> 磁盘缓存 -> 网络下载
|
||||
}
|
||||
|
||||
func store(_ image: UIImage, for url: String) {
|
||||
// 存储到内存和磁盘缓存
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 数据分页加载
|
||||
```swift
|
||||
// PaginationManager.swift
|
||||
class PaginationManager<T>: ObservableObject {
|
||||
@Published var items: [T] = []
|
||||
@Published var isLoading = false
|
||||
@Published var hasMoreData = true
|
||||
|
||||
private var currentPage = 0
|
||||
private let pageSize = 20
|
||||
|
||||
func loadNextPage() async {
|
||||
guard !isLoading && hasMoreData else { return }
|
||||
|
||||
isLoading = true
|
||||
defer { isLoading = false }
|
||||
|
||||
// 加载下一页数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 UI性能优化
|
||||
|
||||
#### LazyLoading实现
|
||||
```swift
|
||||
// LazyImageView.swift
|
||||
struct LazyImageView: View {
|
||||
let url: String
|
||||
@State private var image: UIImage?
|
||||
@State private var isLoading = true
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if let image = image {
|
||||
Image(uiImage: image)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
} else if isLoading {
|
||||
ProgressView()
|
||||
} else {
|
||||
Image(systemName: "photo")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
loadImage()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadImage() {
|
||||
Task {
|
||||
image = await ImageCache.shared.image(for: url)
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 安全性增强
|
||||
|
||||
### 5.1 数据加密
|
||||
```swift
|
||||
// EncryptionService.swift
|
||||
protocol EncryptionServiceProtocol {
|
||||
func encrypt(_ data: Data) throws -> Data
|
||||
func decrypt(_ encryptedData: Data) throws -> Data
|
||||
}
|
||||
|
||||
class EncryptionService: EncryptionServiceProtocol {
|
||||
private let key: SymmetricKey
|
||||
|
||||
init() {
|
||||
// 从Keychain获取或生成密钥
|
||||
self.key = SymmetricKey(size: .bits256)
|
||||
}
|
||||
|
||||
func encrypt(_ data: Data) throws -> Data {
|
||||
let sealedBox = try AES.GCM.seal(data, using: key)
|
||||
return sealedBox.combined!
|
||||
}
|
||||
|
||||
func decrypt(_ encryptedData: Data) throws -> Data {
|
||||
let sealedBox = try AES.GCM.SealedBox(combined: encryptedData)
|
||||
return try AES.GCM.open(sealedBox, using: key)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 API安全
|
||||
```swift
|
||||
// APIKeyManager.swift
|
||||
class APIKeyManager {
|
||||
private let keychain = Keychain(service: "com.emotionmuseum.app")
|
||||
|
||||
func storeAPIKey(_ key: String, for service: String) {
|
||||
keychain[service] = key
|
||||
}
|
||||
|
||||
func getAPIKey(for service: String) -> String? {
|
||||
return keychain[service]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 可维护性提升
|
||||
|
||||
### 6.1 代码规范
|
||||
```swift
|
||||
// SwiftLint配置
|
||||
// .swiftlint.yml
|
||||
rules:
|
||||
- line_length
|
||||
- function_body_length
|
||||
- type_body_length
|
||||
- cyclomatic_complexity
|
||||
- force_cast
|
||||
- force_try
|
||||
|
||||
line_length:
|
||||
warning: 120
|
||||
error: 150
|
||||
|
||||
function_body_length:
|
||||
warning: 50
|
||||
error: 100
|
||||
```
|
||||
|
||||
### 6.2 单元测试框架
|
||||
```swift
|
||||
// ConversationViewModelTests.swift
|
||||
@MainActor
|
||||
class ConversationViewModelTests: XCTestCase {
|
||||
var viewModel: ConversationViewModel!
|
||||
var mockRepository: MockConversationRepository!
|
||||
var mockAIService: MockAIService!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
mockRepository = MockConversationRepository()
|
||||
mockAIService = MockAIService()
|
||||
viewModel = ConversationViewModel(
|
||||
repository: mockRepository,
|
||||
aiService: mockAIService
|
||||
)
|
||||
}
|
||||
|
||||
func testLoadConversations() async {
|
||||
// 测试加载对话功能
|
||||
await viewModel.loadConversations()
|
||||
|
||||
XCTAssertFalse(viewModel.isLoading)
|
||||
XCTAssertEqual(viewModel.conversations.count, mockRepository.mockConversations.count)
|
||||
}
|
||||
|
||||
func testSendMessage() async {
|
||||
// 测试发送消息功能
|
||||
let testMessage = "Hello"
|
||||
await viewModel.sendMessage(testMessage)
|
||||
|
||||
XCTAssertTrue(mockAIService.sendMessageCalled)
|
||||
XCTAssertEqual(mockAIService.lastMessage, testMessage)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 文档和注释规范
|
||||
```swift
|
||||
/// 对话管理的ViewModel
|
||||
///
|
||||
/// 负责管理用户对话的状态和业务逻辑,包括:
|
||||
/// - 加载历史对话
|
||||
/// - 发送和接收消息
|
||||
/// - AI服务集成
|
||||
/// - 错误处理
|
||||
@MainActor
|
||||
class ConversationViewModel: BaseViewModel {
|
||||
|
||||
/// 当前显示的对话列表
|
||||
@Published var conversations: [Conversation] = []
|
||||
|
||||
/// 当前活跃的对话
|
||||
@Published var currentConversation: Conversation?
|
||||
|
||||
/// 加载用户的所有对话
|
||||
/// - Returns: 无返回值,结果通过 `conversations` 属性发布
|
||||
func loadConversations() async {
|
||||
// 实现逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*本文档提供了完整的技术架构完善建议,建议按阶段逐步实施*
|
||||
@@ -1,77 +0,0 @@
|
||||
-- ============================================================================
|
||||
-- Coze API调用记录表优化迁移脚本
|
||||
-- 执行时间: 2025-07-13
|
||||
-- 说明: 为coze_api_call表添加新字段以完整保存接口调用详情
|
||||
-- ============================================================================
|
||||
|
||||
USE emotion_museum;
|
||||
|
||||
-- 备份现有数据(可选)
|
||||
-- CREATE TABLE coze_api_call_backup AS SELECT * FROM coze_api_call;
|
||||
|
||||
-- 添加用户消息相关字段
|
||||
ALTER TABLE coze_api_call
|
||||
ADD COLUMN user_message TEXT COMMENT '用户输入的消息内容' AFTER request_headers,
|
||||
ADD COLUMN user_message_type VARCHAR(20) DEFAULT 'text' COMMENT '用户消息类型: text/image/file' AFTER user_message;
|
||||
|
||||
-- 添加AI回复相关字段
|
||||
ALTER TABLE coze_api_call
|
||||
ADD COLUMN ai_reply TEXT COMMENT 'AI回复的消息内容' AFTER user_message_type,
|
||||
ADD COLUMN ai_reply_type VARCHAR(20) DEFAULT 'text' COMMENT 'AI回复类型: text/image/file' AFTER ai_reply;
|
||||
|
||||
-- 添加轮询相关字段
|
||||
ALTER TABLE coze_api_call
|
||||
ADD COLUMN poll_count INT DEFAULT 0 COMMENT '轮询次数' AFTER response_headers,
|
||||
ADD COLUMN poll_start_time DATETIME COMMENT '轮询开始时间' AFTER poll_count,
|
||||
ADD COLUMN poll_end_time DATETIME COMMENT '轮询结束时间' AFTER poll_start_time,
|
||||
ADD COLUMN final_status VARCHAR(20) COMMENT '最终状态: completed/failed/timeout' AFTER poll_end_time;
|
||||
|
||||
-- 添加功能调用相关字段
|
||||
ALTER TABLE coze_api_call
|
||||
ADD COLUMN function_calls JSON COMMENT '函数调用记录' AFTER total_tokens,
|
||||
ADD COLUMN function_results JSON COMMENT '函数调用结果' AFTER function_calls;
|
||||
|
||||
-- 添加扩展信息字段
|
||||
ALTER TABLE coze_api_call
|
||||
ADD COLUMN client_ip VARCHAR(45) COMMENT '客户端IP' AFTER error_message,
|
||||
ADD COLUMN user_agent TEXT COMMENT '用户代理' AFTER client_ip,
|
||||
ADD COLUMN session_id VARCHAR(100) COMMENT '会话ID' AFTER user_agent,
|
||||
ADD COLUMN trace_id VARCHAR(100) COMMENT '追踪ID' AFTER session_id,
|
||||
ADD COLUMN metadata JSON COMMENT '扩展元数据' AFTER trace_id;
|
||||
|
||||
-- 添加新字段的索引
|
||||
CREATE INDEX idx_coze_api_call_final_status ON coze_api_call (final_status);
|
||||
CREATE INDEX idx_coze_api_call_client_ip ON coze_api_call (client_ip);
|
||||
CREATE INDEX idx_coze_api_call_session_id ON coze_api_call (session_id);
|
||||
CREATE INDEX idx_coze_api_call_trace_id ON coze_api_call (trace_id);
|
||||
CREATE INDEX idx_coze_api_call_user_status ON coze_api_call (user_id, status);
|
||||
CREATE INDEX idx_coze_api_call_conversation_time ON coze_api_call (conversation_id, start_time);
|
||||
|
||||
-- 更新表注释
|
||||
ALTER TABLE coze_api_call COMMENT = 'Coze API调用记录表 - 完整版本';
|
||||
|
||||
-- 验证表结构
|
||||
DESCRIBE coze_api_call;
|
||||
|
||||
-- 显示表的索引
|
||||
SHOW INDEX FROM coze_api_call;
|
||||
|
||||
-- 统计现有数据
|
||||
SELECT
|
||||
COUNT(*) as total_records,
|
||||
COUNT(DISTINCT user_id) as unique_users,
|
||||
COUNT(DISTINCT conversation_id) as unique_conversations,
|
||||
MIN(create_time) as earliest_record,
|
||||
MAX(create_time) as latest_record
|
||||
FROM coze_api_call;
|
||||
|
||||
-- 显示各状态的记录数
|
||||
SELECT status, COUNT(*) as count
|
||||
FROM coze_api_call
|
||||
GROUP BY status;
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- ============================================================================
|
||||
-- 迁移完成
|
||||
-- ============================================================================
|
||||
@@ -1,315 +0,0 @@
|
||||
# 情感博物馆 Jenkins Pipeline 配置指南
|
||||
|
||||
## 概述
|
||||
|
||||
本文档描述了优化后的Jenkins CI/CD流水线配置,采用分离式部署架构:
|
||||
- **构建阶段**: 在Jenkins服务器上编译打包所有微服务
|
||||
- **部署阶段**: 将jar包传输到远程应用服务器并进行容器化部署
|
||||
|
||||
## 部署脚本架构
|
||||
|
||||
### 1. 脚本分类
|
||||
|
||||
#### 🔨 构建脚本
|
||||
- **`build-all.sh`**: 专门用于Jenkins构建阶段,编译所有微服务jar包
|
||||
- **特点**: 仅在Jenkins服务器执行,不涉及远程操作
|
||||
|
||||
#### 🚀 部署脚本
|
||||
- **`deploy-remote.sh`**: 专门用于远程部署,传输jar包并部署到应用服务器
|
||||
- **特点**: 假设jar包已构建完成,专注于远程部署
|
||||
|
||||
#### 🔄 综合脚本
|
||||
- **`deploy-all.sh`**: 支持多种模式的综合脚本
|
||||
- **模式**:
|
||||
- `full`: 完整模式 (构建+部署)
|
||||
- `build`: 仅构建模式
|
||||
- `deploy`: 仅部署模式
|
||||
|
||||
### 2. 服务列表
|
||||
|
||||
所有脚本支持以下10个微服务:
|
||||
|
||||
| 服务名称 | 端口 | 描述 |
|
||||
|---------|------|------|
|
||||
| emotion-gateway | 19000 | API网关服务 |
|
||||
| emotion-user | 19001 | 用户管理服务 |
|
||||
| emotion-ai | 19002 | AI聊天服务 |
|
||||
| emotion-record | 19003 | 记录管理服务 |
|
||||
| emotion-growth | 19004 | 成长跟踪服务 |
|
||||
| emotion-explore | 19005 | 探索服务 |
|
||||
| emotion-reward | 19006 | 奖励服务 |
|
||||
| emotion-websocket | 19007 | WebSocket服务 |
|
||||
| emotion-auth | 19008 | 认证服务 |
|
||||
| emotion-stats | 19009 | 统计服务 |
|
||||
|
||||
## Jenkins Pipeline 配置
|
||||
|
||||
### 1. 推荐的Pipeline配置
|
||||
|
||||
#### 方案一:分离式Pipeline (推荐)
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
DEPLOY_ENV = 'test'
|
||||
PROJECT_NAME = 'emotion-museum'
|
||||
REMOTE_HOST = 'root@47.111.10.27'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
git branch: 'master', url: 'your-git-repo-url'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
steps {
|
||||
dir('backend') {
|
||||
sh './build-all.sh'
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
// 归档构建产物
|
||||
archiveArtifacts artifacts: 'backend/*/target/*.jar', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy to Remote') {
|
||||
steps {
|
||||
dir('backend') {
|
||||
sh './deploy-remote.sh'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Health Check') {
|
||||
steps {
|
||||
script {
|
||||
// 等待服务启动
|
||||
sleep 30
|
||||
|
||||
// 检查关键服务
|
||||
def services = ['19000', '19001', '19002', '19008']
|
||||
services.each { port ->
|
||||
sh "curl -f http://47.111.10.27:${port}/actuator/health || exit 1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
// 发送部署结果通知
|
||||
emailext (
|
||||
subject: "部署结果: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
|
||||
body: """
|
||||
部署状态: ${currentBuild.result}
|
||||
构建链接: ${env.BUILD_URL}
|
||||
部署环境: ${env.DEPLOY_ENV}
|
||||
""",
|
||||
to: "your-email@example.com"
|
||||
)
|
||||
}
|
||||
success {
|
||||
echo '🎉 部署成功!'
|
||||
}
|
||||
failure {
|
||||
echo '❌ 部署失败,请检查日志'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 方案二:单一Pipeline
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
DEPLOY_ENV = 'test'
|
||||
DEPLOY_MODE = 'full' // full, build, deploy
|
||||
PROJECT_NAME = 'emotion-museum'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
git branch: 'master', url: 'your-git-repo-url'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy') {
|
||||
steps {
|
||||
dir('backend') {
|
||||
sh './deploy-all.sh'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 环境变量配置
|
||||
|
||||
在Jenkins中配置以下环境变量:
|
||||
|
||||
#### 必需变量
|
||||
```bash
|
||||
# 部署配置
|
||||
DEPLOY_ENV=test # 部署环境
|
||||
DEPLOY_HOST=root@47.111.10.27 # 目标服务器
|
||||
PROJECT_NAME=emotion-museum # 项目名称
|
||||
|
||||
# 远程路径配置
|
||||
REMOTE_BUILD_DIR=/data/builds # jar包存储目录
|
||||
REMOTE_DOCKER_DIR=/data/docker # Docker配置目录
|
||||
```
|
||||
|
||||
#### 可选变量
|
||||
```bash
|
||||
# 部署模式 (仅deploy-all.sh使用)
|
||||
DEPLOY_MODE=full # full, build, deploy
|
||||
|
||||
# 数据库配置
|
||||
MYSQL_HOST=47.111.10.27
|
||||
MYSQL_PASSWORD=EmotionMuseum2025*#
|
||||
|
||||
# Nacos配置
|
||||
NACOS_SERVER_ADDR=47.111.10.27:8848
|
||||
NACOS_PASSWORD=Peanut2817*#
|
||||
```
|
||||
|
||||
### 3. 多环境部署配置
|
||||
|
||||
#### 测试环境
|
||||
```groovy
|
||||
environment {
|
||||
DEPLOY_ENV = 'test'
|
||||
DEPLOY_HOST = 'root@47.111.10.27'
|
||||
}
|
||||
```
|
||||
|
||||
#### 生产环境
|
||||
```groovy
|
||||
environment {
|
||||
DEPLOY_ENV = 'prod'
|
||||
DEPLOY_HOST = 'root@production-server'
|
||||
}
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 本地测试
|
||||
|
||||
#### 仅构建
|
||||
```bash
|
||||
cd backend
|
||||
./build-all.sh
|
||||
```
|
||||
|
||||
#### 仅部署 (需要先有jar包)
|
||||
```bash
|
||||
cd backend
|
||||
./deploy-remote.sh
|
||||
```
|
||||
|
||||
#### 完整部署
|
||||
```bash
|
||||
cd backend
|
||||
./deploy-all.sh
|
||||
# 或指定模式
|
||||
DEPLOY_MODE=full ./deploy-all.sh
|
||||
```
|
||||
|
||||
### 2. Jenkins执行
|
||||
|
||||
#### 分离式执行
|
||||
```bash
|
||||
# 构建阶段
|
||||
./build-all.sh
|
||||
|
||||
# 部署阶段
|
||||
./deploy-remote.sh
|
||||
```
|
||||
|
||||
#### 综合执行
|
||||
```bash
|
||||
# 根据DEPLOY_MODE环境变量决定执行模式
|
||||
./deploy-all.sh
|
||||
```
|
||||
|
||||
## 优势特点
|
||||
|
||||
### 1. 🔄 分离式架构
|
||||
- **构建与部署分离**: Jenkins服务器专注构建,应用服务器专注运行
|
||||
- **资源优化**: 避免在应用服务器上安装构建工具
|
||||
- **安全性**: 减少应用服务器的攻击面
|
||||
|
||||
### 2. 🛡️ 容错机制
|
||||
- **单服务失败不影响其他服务**: 继续部署其他服务
|
||||
- **详细错误报告**: 每个服务的部署状态和错误信息
|
||||
- **回滚支持**: 保留旧版本容器,支持快速回滚
|
||||
|
||||
### 3. 📊 监控与报告
|
||||
- **实时日志**: 详细的部署过程日志
|
||||
- **健康检查**: 自动验证服务启动状态
|
||||
- **部署报告**: 完整的部署统计和结果报告
|
||||
|
||||
### 4. 🔧 灵活配置
|
||||
- **多模式支持**: 支持仅构建、仅部署、完整部署
|
||||
- **环境变量**: 支持Jenkins环境变量覆盖
|
||||
- **多环境**: 支持test/prod等多环境部署
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 1. 构建失败
|
||||
```bash
|
||||
# 检查Java和Maven版本
|
||||
java -version
|
||||
mvn -version
|
||||
|
||||
# 查看详细构建日志
|
||||
./build-all.sh
|
||||
```
|
||||
|
||||
### 2. 部署失败
|
||||
```bash
|
||||
# 检查SSH连接
|
||||
ssh 'root@47.111.10.27' "echo 'test'"
|
||||
|
||||
# 检查远程Docker环境
|
||||
ssh 'root@47.111.10.27' "docker --version"
|
||||
|
||||
# 查看容器日志
|
||||
ssh 'root@47.111.10.27' "docker logs <service_name>"
|
||||
```
|
||||
|
||||
### 3. 服务启动失败
|
||||
```bash
|
||||
# 检查端口占用
|
||||
ssh 'root@47.111.10.27' "netstat -tlnp | grep <port>"
|
||||
|
||||
# 检查服务健康状态
|
||||
curl -f http://47.111.10.27:<port>/actuator/health
|
||||
```
|
||||
|
||||
## 联系支持
|
||||
|
||||
如遇到问题,请:
|
||||
1. 查看Jenkins构建日志
|
||||
2. 检查脚本执行日志
|
||||
3. 验证环境变量配置
|
||||
4. 联系开发团队并提供完整日志
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v2.0
|
||||
**更新时间**: 2025-07-18
|
||||
**维护团队**: 情感博物馆开发团队
|
||||
@@ -1,324 +0,0 @@
|
||||
# 情感博物馆 Jenkins 部署说明
|
||||
|
||||
## 概述
|
||||
|
||||
本文档描述如何在Jenkins中配置和使用部署脚本来自动化部署情感博物馆项目的后端微服务和前端应用。
|
||||
|
||||
## 部署脚本说明
|
||||
|
||||
### 1. 后端微服务部署
|
||||
|
||||
#### 主部署脚本
|
||||
- **文件路径**: `backend/deploy-all.sh`
|
||||
- **功能**: 一键部署所有后端微服务
|
||||
- **特性**:
|
||||
- 支持单个服务失败不影响其他服务部署
|
||||
- 详细的部署日志和错误报告
|
||||
- 支持Jenkins环境变量
|
||||
- 容器化部署到远程服务器
|
||||
|
||||
#### 单服务部署脚本
|
||||
每个微服务模块都有独立的部署脚本:
|
||||
- `backend/emotion-gateway/deploy.sh` - 网关服务
|
||||
- `backend/emotion-user/deploy.sh` - 用户服务
|
||||
- `backend/emotion-ai/deploy.sh` - AI服务
|
||||
- `backend/emotion-record/deploy.sh` - 记录服务
|
||||
- `backend/emotion-growth/deploy.sh` - 成长服务
|
||||
- `backend/emotion-websocket/deploy.sh` - WebSocket服务
|
||||
- `backend/emotion-auth/deploy.sh` - 认证服务
|
||||
|
||||
### 2. 前端应用部署
|
||||
|
||||
#### 前端部署脚本
|
||||
- **文件路径**: `web-flowith/deploy.sh`
|
||||
- **功能**: 构建并部署前端应用到远程服务器
|
||||
- **特性**:
|
||||
- 自动构建Vue应用
|
||||
- 备份旧版本
|
||||
- 配置Nginx反向代理
|
||||
- 健康检查
|
||||
|
||||
## Jenkins配置
|
||||
|
||||
### 1. 环境变量配置
|
||||
|
||||
在Jenkins中配置以下环境变量:
|
||||
|
||||
#### 必需变量
|
||||
```bash
|
||||
# 部署目标服务器
|
||||
DEPLOY_HOST=root@47.111.10.27
|
||||
|
||||
# 后端部署配置
|
||||
REMOTE_BUILD_DIR=/data/builds
|
||||
REMOTE_DOCKER_DIR=/data/docker
|
||||
DEPLOY_ENV=test
|
||||
PROJECT_NAME=emotion-museum
|
||||
|
||||
# 前端部署配置
|
||||
REMOTE_WEB_DIR=/data/www/emotion-museum
|
||||
```
|
||||
|
||||
#### 可选变量
|
||||
```bash
|
||||
# 数据库配置
|
||||
MYSQL_HOST=47.111.10.27
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_DATABASE=emotion_museum
|
||||
MYSQL_USERNAME=root
|
||||
|
||||
# Redis配置
|
||||
REDIS_HOST=47.111.10.27
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=
|
||||
REDIS_DATABASE=0
|
||||
|
||||
# Nacos配置
|
||||
NACOS_SERVER_ADDR=47.111.10.27:8848
|
||||
NACOS_USERNAME=nacos
|
||||
NACOS_PASSWORD=Peanut2817*#
|
||||
|
||||
# AI服务配置
|
||||
COZE_API_TOKEN=your_coze_api_token
|
||||
|
||||
# JWT配置
|
||||
JWT_SECRET=emotion-museum-secret-key-2025
|
||||
```
|
||||
|
||||
### 2. Jenkins Pipeline 配置
|
||||
|
||||
#### 后端微服务Pipeline
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
DEPLOY_HOST = 'root@47.111.10.27'
|
||||
DEPLOY_ENV = 'test'
|
||||
PROJECT_NAME = 'emotion-museum'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
git branch: 'main', url: 'your-git-repo-url'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy Backend Services') {
|
||||
steps {
|
||||
dir('backend') {
|
||||
sh './deploy-all.sh'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
// 发送部署结果通知
|
||||
emailext (
|
||||
subject: "部署结果: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
|
||||
body: "部署状态: ${currentBuild.result}\n构建链接: ${env.BUILD_URL}",
|
||||
to: "your-email@example.com"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 前端应用Pipeline
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
DEPLOY_HOST = 'root@47.111.10.27'
|
||||
REMOTE_WEB_DIR = '/data/www/emotion-museum'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
git branch: 'main', url: 'your-git-repo-url'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy Frontend') {
|
||||
steps {
|
||||
dir('web-flowith') {
|
||||
sh './deploy.sh'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
emailext (
|
||||
subject: "前端部署结果: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
|
||||
body: "部署状态: ${currentBuild.result}\n访问地址: http://47.111.10.27/emotion-museum/",
|
||||
to: "your-email@example.com"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 单服务部署Job配置
|
||||
|
||||
为每个微服务创建单独的Jenkins Job:
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
parameters {
|
||||
choice(
|
||||
name: 'SERVICE_NAME',
|
||||
choices: ['emotion-gateway', 'emotion-user', 'emotion-ai', 'emotion-record', 'emotion-growth', 'emotion-websocket', 'emotion-auth'],
|
||||
description: '选择要部署的服务'
|
||||
)
|
||||
}
|
||||
|
||||
environment {
|
||||
DEPLOY_HOST = 'root@47.111.10.27'
|
||||
DEPLOY_ENV = 'test'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
git branch: 'main', url: 'your-git-repo-url'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy Single Service') {
|
||||
steps {
|
||||
dir("backend/${params.SERVICE_NAME}") {
|
||||
sh './deploy.sh'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 部署流程
|
||||
|
||||
### 1. 全量部署流程
|
||||
|
||||
1. **代码检出**: 从Git仓库拉取最新代码
|
||||
2. **环境检查**: 检查远程服务器连接和本地构建环境
|
||||
3. **服务构建**: 使用Maven构建所有微服务
|
||||
4. **容器部署**: 逐个部署服务到Docker容器
|
||||
5. **健康检查**: 验证服务启动状态
|
||||
6. **部署报告**: 生成详细的部署结果报告
|
||||
|
||||
### 2. 单服务部署流程
|
||||
|
||||
1. **服务构建**: 构建指定的微服务
|
||||
2. **容器更新**: 停止旧容器,启动新容器
|
||||
3. **健康检查**: 验证服务状态
|
||||
4. **结果反馈**: 返回部署结果
|
||||
|
||||
### 3. 前端部署流程
|
||||
|
||||
1. **依赖安装**: 安装Node.js依赖
|
||||
2. **项目构建**: 构建Vue生产版本
|
||||
3. **文件上传**: 上传构建产物到服务器
|
||||
4. **Nginx配置**: 配置反向代理和静态文件服务
|
||||
5. **健康检查**: 验证前端页面和API代理
|
||||
|
||||
## 监控和日志
|
||||
|
||||
### 1. 部署日志
|
||||
|
||||
- **位置**: Jenkins构建日志
|
||||
- **内容**: 详细的部署步骤和错误信息
|
||||
- **格式**: 带时间戳和颜色标识的结构化日志
|
||||
|
||||
### 2. 应用日志
|
||||
|
||||
- **后端日志**: `/data/logs/emotion-museum/`
|
||||
- **Nginx日志**: `/data/logs/nginx/`
|
||||
- **容器日志**: `docker logs <container_name>`
|
||||
|
||||
### 3. 健康检查
|
||||
|
||||
- **后端服务**: `http://47.111.10.27:<port>/actuator/health`
|
||||
- **前端应用**: `http://47.111.10.27/emotion-museum/`
|
||||
- **API代理**: `http://47.111.10.27/api/`
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 1. 常见问题
|
||||
|
||||
#### 服务启动失败
|
||||
```bash
|
||||
# 查看容器日志
|
||||
docker logs <service_name>
|
||||
|
||||
# 查看容器状态
|
||||
docker ps -a | grep emotion
|
||||
|
||||
# 重启服务
|
||||
docker restart <service_name>
|
||||
```
|
||||
|
||||
#### 网络连接问题
|
||||
```bash
|
||||
# 检查端口占用
|
||||
netstat -tlnp | grep <port>
|
||||
|
||||
# 检查防火墙
|
||||
ufw status
|
||||
|
||||
# 测试服务连通性
|
||||
curl -f http://localhost:<port>/actuator/health
|
||||
```
|
||||
|
||||
#### 前端访问问题
|
||||
```bash
|
||||
# 检查Nginx配置
|
||||
nginx -t
|
||||
|
||||
# 重载Nginx配置
|
||||
systemctl reload nginx
|
||||
|
||||
# 查看Nginx日志
|
||||
tail -f /data/logs/nginx/emotion-museum-error.log
|
||||
```
|
||||
|
||||
### 2. 回滚操作
|
||||
|
||||
#### 后端服务回滚
|
||||
```bash
|
||||
# 停止当前容器
|
||||
docker stop <service_name>
|
||||
|
||||
# 启动备份版本
|
||||
docker run -d --name <service_name> <backup_image>
|
||||
```
|
||||
|
||||
#### 前端应用回滚
|
||||
```bash
|
||||
# 恢复备份版本
|
||||
cd /data/www/emotion-museum/backup
|
||||
cp -r backup_<timestamp> ../web-flowith
|
||||
```
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
1. **SSH密钥管理**: 确保Jenkins服务器的SSH密钥安全
|
||||
2. **环境变量**: 敏感信息使用Jenkins凭据管理
|
||||
3. **网络安全**: 限制服务器访问权限
|
||||
4. **日志安全**: 避免在日志中暴露敏感信息
|
||||
|
||||
## 联系信息
|
||||
|
||||
如有问题,请联系开发团队:
|
||||
- 邮箱: dev@emotion-museum.com
|
||||
- 文档更新: 2025-07-18
|
||||
@@ -1,308 +0,0 @@
|
||||
# 情感博物馆部署脚本使用说明
|
||||
|
||||
## 概述
|
||||
|
||||
本项目提供了完整的自动化部署脚本,支持本地部署和Jenkins CI/CD部署。所有脚本都经过优化,支持错误处理、详细日志输出和部署状态报告。
|
||||
|
||||
## 脚本列表
|
||||
|
||||
### 后端微服务部署脚本
|
||||
|
||||
#### 1. 全量部署脚本
|
||||
- **路径**: `backend/deploy-all.sh`
|
||||
- **功能**: 一键部署所有后端微服务
|
||||
- **特性**:
|
||||
- ✅ 单个服务失败不影响其他服务
|
||||
- ✅ 详细的部署报告和错误日志
|
||||
- ✅ 支持Jenkins环境变量
|
||||
- ✅ 容器化部署
|
||||
|
||||
#### 2. 单服务部署脚本
|
||||
每个微服务都有独立的部署脚本:
|
||||
- `backend/emotion-gateway/deploy.sh` - API网关服务
|
||||
- `backend/emotion-user/deploy.sh` - 用户管理服务
|
||||
- `backend/emotion-ai/deploy.sh` - AI聊天服务
|
||||
- `backend/emotion-record/deploy.sh` - 记录管理服务
|
||||
- `backend/emotion-growth/deploy.sh` - 成长跟踪服务
|
||||
- `backend/emotion-websocket/deploy.sh` - WebSocket服务
|
||||
- `backend/emotion-auth/deploy.sh` - 认证服务
|
||||
|
||||
### 前端应用部署脚本
|
||||
|
||||
#### 3. 前端部署脚本
|
||||
- **路径**: `web-flowith/deploy.sh`
|
||||
- **功能**: 构建并部署Vue前端应用
|
||||
- **特性**:
|
||||
- ✅ 自动构建和优化
|
||||
- ✅ 备份旧版本
|
||||
- ✅ Nginx配置
|
||||
- ✅ 健康检查
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 本地部署
|
||||
|
||||
#### 部署所有后端服务
|
||||
```bash
|
||||
cd backend
|
||||
./deploy-all.sh
|
||||
```
|
||||
|
||||
#### 部署单个后端服务
|
||||
```bash
|
||||
cd backend/emotion-gateway
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
#### 部署前端应用
|
||||
```bash
|
||||
cd web-flowith
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
### Jenkins部署
|
||||
|
||||
#### 环境变量配置
|
||||
在Jenkins中设置以下环境变量:
|
||||
|
||||
```bash
|
||||
# 必需变量
|
||||
DEPLOY_HOST=root@47.111.10.27
|
||||
DEPLOY_ENV=test
|
||||
PROJECT_NAME=emotion-museum
|
||||
|
||||
# 可选变量(使用默认值)
|
||||
REMOTE_BUILD_DIR=/data/builds
|
||||
REMOTE_DOCKER_DIR=/data/docker
|
||||
REMOTE_WEB_DIR=/data/www/emotion-museum
|
||||
```
|
||||
|
||||
#### Pipeline脚本示例
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
DEPLOY_HOST = 'root@47.111.10.27'
|
||||
DEPLOY_ENV = 'test'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Deploy Backend') {
|
||||
steps {
|
||||
dir('backend') {
|
||||
sh './deploy-all.sh'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy Frontend') {
|
||||
steps {
|
||||
dir('web-flowith') {
|
||||
sh './deploy.sh'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 部署配置
|
||||
|
||||
### 服务端口分配
|
||||
- **API网关**: 19000
|
||||
- **用户服务**: 19001
|
||||
- **AI服务**: 19002
|
||||
- **记录服务**: 19003
|
||||
- **成长服务**: 19004
|
||||
- **WebSocket服务**: 19007
|
||||
- **认证服务**: 19008
|
||||
|
||||
### 远程服务器目录结构
|
||||
```
|
||||
/data/
|
||||
├── builds/ # JAR包存储目录
|
||||
│ ├── emotion-gateway-1.0.0.jar
|
||||
│ ├── emotion-user-1.0.0.jar
|
||||
│ └── ...
|
||||
├── docker/ # Docker配置目录
|
||||
│ ├── Dockerfile.emotion-gateway
|
||||
│ ├── Dockerfile.emotion-user
|
||||
│ └── ...
|
||||
├── www/emotion-museum/ # 前端文件目录
|
||||
│ ├── web-flowith/ # 前端应用
|
||||
│ └── backup/ # 前端备份
|
||||
└── logs/ # 日志目录
|
||||
├── emotion-museum/ # 应用日志
|
||||
└── nginx/ # Nginx日志
|
||||
```
|
||||
|
||||
## 部署报告示例
|
||||
|
||||
### 后端服务部署报告
|
||||
```
|
||||
========================================
|
||||
部署完成报告
|
||||
========================================
|
||||
项目名称: emotion-museum
|
||||
部署环境: test
|
||||
目标服务器: root@47.111.10.27
|
||||
部署时间: 2025-07-18 14:30:25
|
||||
总耗时: 180s
|
||||
Jenkins构建: #42
|
||||
========================================
|
||||
|
||||
📊 部署统计:
|
||||
总服务数: 7
|
||||
成功部署: 6
|
||||
失败部署: 1
|
||||
成功率: 85%
|
||||
|
||||
📋 服务部署详情:
|
||||
服务名称 状态 耗时 备注
|
||||
----------------------------------------
|
||||
emotion-gateway ✅ 成功 25s http://47.111.10.27:19000
|
||||
emotion-user ✅ 成功 30s http://47.111.10.27:19001
|
||||
emotion-ai ✅ 成功 35s http://47.111.10.27:19002
|
||||
emotion-record ✅ 成功 28s http://47.111.10.27:19003
|
||||
emotion-growth ✅ 成功 32s http://47.111.10.27:19004
|
||||
emotion-websocket ✅ 成功 20s http://47.111.10.27:19007
|
||||
emotion-auth ❌ 失败 10s 查看错误日志
|
||||
|
||||
🐳 当前容器运行状态:
|
||||
----------------------------------------
|
||||
NAMES STATUS PORTS
|
||||
emotion-gateway Up 2 minutes 0.0.0.0:19000->19000/tcp
|
||||
emotion-user Up 2 minutes 0.0.0.0:19001->19001/tcp
|
||||
emotion-ai Up 1 minute 0.0.0.0:19002->19002/tcp
|
||||
...
|
||||
```
|
||||
|
||||
### 前端部署报告
|
||||
```
|
||||
========================================
|
||||
前端部署完成报告
|
||||
========================================
|
||||
项目名称: emotion-museum-frontend
|
||||
目标服务器: root@47.111.10.27
|
||||
部署路径: /data/www/emotion-museum/web-flowith
|
||||
部署时间: 2025-07-18 14:35:10
|
||||
总耗时: 45s
|
||||
========================================
|
||||
|
||||
🌐 访问地址:
|
||||
前端页面: http://47.111.10.27/emotion-museum/
|
||||
API接口: http://47.111.10.27/api/
|
||||
|
||||
📁 远程文件信息:
|
||||
部署目录大小: 2.3M
|
||||
主要文件:
|
||||
-rw-r--r-- 1 www-data www-data 1.2K index.html
|
||||
drwxr-xr-x 2 www-data www-data 4.0K assets/
|
||||
drwxr-xr-x 2 www-data www-data 4.0K images/
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 常见问题及解决方案
|
||||
|
||||
#### 1. SSH连接失败
|
||||
```bash
|
||||
# 检查SSH密钥
|
||||
ssh -T root@47.111.10.27
|
||||
|
||||
# 检查网络连通性
|
||||
ping 47.111.10.27
|
||||
```
|
||||
|
||||
#### 2. 服务构建失败
|
||||
```bash
|
||||
# 检查Java版本
|
||||
java -version
|
||||
|
||||
# 检查Maven配置
|
||||
mvn -version
|
||||
|
||||
# 清理并重新构建
|
||||
mvn clean compile
|
||||
```
|
||||
|
||||
#### 3. 容器启动失败
|
||||
```bash
|
||||
# 查看容器日志
|
||||
docker logs <container_name>
|
||||
|
||||
# 检查端口占用
|
||||
netstat -tlnp | grep <port>
|
||||
|
||||
# 检查Docker网络
|
||||
docker network ls
|
||||
```
|
||||
|
||||
#### 4. 前端构建失败
|
||||
```bash
|
||||
# 检查Node.js版本
|
||||
node --version
|
||||
|
||||
# 清理依赖重新安装
|
||||
rm -rf node_modules package-lock.json
|
||||
npm install
|
||||
```
|
||||
|
||||
### 日志查看
|
||||
|
||||
#### 部署日志
|
||||
- Jenkins构建日志中包含完整的部署过程
|
||||
- 每个步骤都有详细的时间戳和状态信息
|
||||
|
||||
#### 应用日志
|
||||
```bash
|
||||
# 查看容器日志
|
||||
docker logs -f <service_name>
|
||||
|
||||
# 查看应用日志文件
|
||||
tail -f /data/logs/emotion-museum/<service_name>.log
|
||||
|
||||
# 查看Nginx日志
|
||||
tail -f /data/logs/nginx/emotion-museum-access.log
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 部署前检查
|
||||
- ✅ 确认代码已提交到正确分支
|
||||
- ✅ 检查远程服务器资源使用情况
|
||||
- ✅ 备份重要数据
|
||||
- ✅ 通知相关人员部署计划
|
||||
|
||||
### 2. 部署过程监控
|
||||
- ✅ 实时查看部署日志
|
||||
- ✅ 监控服务器资源使用
|
||||
- ✅ 检查服务健康状态
|
||||
- ✅ 验证功能正常性
|
||||
|
||||
### 3. 部署后验证
|
||||
- ✅ 访问前端页面确认正常
|
||||
- ✅ 测试API接口功能
|
||||
- ✅ 检查日志无异常
|
||||
- ✅ 监控服务性能指标
|
||||
|
||||
### 4. 回滚准备
|
||||
- ✅ 保留旧版本备份
|
||||
- ✅ 准备回滚脚本
|
||||
- ✅ 制定回滚计划
|
||||
- ✅ 测试回滚流程
|
||||
|
||||
## 联系支持
|
||||
|
||||
如遇到部署问题,请:
|
||||
|
||||
1. **查看部署日志**: 详细的错误信息通常在日志中
|
||||
2. **检查服务状态**: 使用健康检查接口验证服务状态
|
||||
3. **联系开发团队**: 提供完整的错误日志和环境信息
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**更新时间**: 2025-07-18
|
||||
**维护团队**: 情感博物馆开发团队
|
||||
Reference in New Issue
Block a user