feat: 完善entity-db-sync和maven-assembly技能包 - 增强部署目录管理和实践规范
This commit is contained in:
parent
e5d9db10a8
commit
fb6554f32c
286
.qoder/skills/entity-db-sync/SKILL.md
Normal file
286
.qoder/skills/entity-db-sync/SKILL.md
Normal file
@ -0,0 +1,286 @@
|
||||
---
|
||||
name: entity-db-sync
|
||||
description: 确保Java实体类与数据库SQL脚本同步的技能,当修改实体类字段时自动检查并更新对应的数据库初始化脚本,保证表结构与实体定义严格一致。使用场景:修改实体类属性、添加字段、删除字段、字段类型变更时自动触发。实践要求:同步更新设计文档中的数据表信息,独立目录保存变更脚本便于生产环境更新。
|
||||
---
|
||||
|
||||
# 实体类与数据库脚本同步技能
|
||||
|
||||
## 触发条件
|
||||
|
||||
当出现以下情况时自动应用此技能:
|
||||
|
||||
1. **实体类修改相关**:
|
||||
- 修改Java实体类的字段定义
|
||||
- 添加新的实体类字段
|
||||
- 删除实体类字段
|
||||
- 修改字段的数据类型或注解
|
||||
|
||||
2. **数据库脚本相关**:
|
||||
- 需要更新数据库初始化SQL脚本
|
||||
- 需要创建新的表结构SQL
|
||||
- 需要修改现有表的字段定义
|
||||
|
||||
3. **同步检查相关**:
|
||||
- 需要验证实体类与数据库脚本的一致性
|
||||
- 需要生成差异报告
|
||||
- 需要修复不一致的地方
|
||||
|
||||
4. **文档维护相关**:
|
||||
- 需要同步更新设计文档中的表结构信息
|
||||
- 需要生成数据库变更脚本
|
||||
- 需要维护生产环境更新包
|
||||
|
||||
## 核心原则
|
||||
|
||||
### 同步规范
|
||||
- **一对一映射**:每个实体类字段必须对应数据库表中的列
|
||||
- **类型匹配**:Java数据类型与MySQL数据类型必须兼容
|
||||
- **约束一致**:非空约束、长度限制等必须保持一致
|
||||
- **注解驱动**:基于JPA/Hibernate注解生成SQL定义
|
||||
|
||||
### 文档同步规范
|
||||
- **设计文档更新**:实体类变更时同步更新相关设计文档
|
||||
- **变更脚本管理**:独立目录保存数据库变更脚本
|
||||
- **版本控制**:维护清晰的变更历史和版本信息
|
||||
|
||||
### 生产环境部署规范
|
||||
- **变更脚本独立存储**:便于生产环境按需执行
|
||||
- **回滚方案准备**:每个变更都提供回滚脚本
|
||||
- **影响评估**:评估变更对现有数据的影响
|
||||
|
||||
## 实践要求
|
||||
|
||||
### 1. 设计文档同步更新
|
||||
|
||||
#### 需要维护的文档类型
|
||||
- **数据库设计文档**:表结构定义、字段说明、约束条件
|
||||
- **API接口文档**:涉及数据模型变更的接口说明
|
||||
- **业务流程文档**:受数据结构影响的业务逻辑说明
|
||||
|
||||
#### 文档更新流程
|
||||
```
|
||||
1. 实体类修改 → 2. 生成SQL变更脚本 → 3. 更新设计文档 → 4. 验证一致性
|
||||
```
|
||||
|
||||
#### 文档更新检查清单
|
||||
- [ ] 数据库表结构调整说明
|
||||
- [ ] 字段新增/删除/修改记录
|
||||
- [ ] 约束条件变更说明
|
||||
- [ ] 索引变更记录
|
||||
- [ ] 业务影响评估
|
||||
|
||||
### 2. 变更脚本管理
|
||||
|
||||
#### 目录结构规范
|
||||
```
|
||||
project/
|
||||
├── change/ # 部署相关文件(与开发代码分离)
|
||||
│ └── sql/
|
||||
│ ├── init/ # 初始化脚本(首次部署)
|
||||
│ │ ├── user.sql
|
||||
│ │ ├── order.sql
|
||||
│ │ └── product.sql
|
||||
│ └── upgrade/ # 升级脚本(版本变更)
|
||||
│ ├── v1.1.0/
|
||||
│ │ ├── 20240115_add_user_phone.sql
|
||||
│ │ ├── 20240115_modify_order_amount_precision.sql
|
||||
│ │ └── rollback/
|
||||
│ │ ├── 20240115_add_user_phone_rollback.sql
|
||||
│ └── v1.2.0/
|
||||
│ └── 20240201_add_product_category.sql
|
||||
└── src/main/resources/ # 开发代码目录(保持独立)
|
||||
```
|
||||
|
||||
#### 变更脚本命名规范
|
||||
```bash
|
||||
# 格式:YYYYMMDD_description.sql
|
||||
20240115_add_user_phone.sql # 正向变更
|
||||
20240115_add_user_phone_rollback.sql # 回滚脚本
|
||||
20240115_add_user_phone_verify.sql # 验证脚本
|
||||
```
|
||||
|
||||
#### 脚本内容模板
|
||||
```sql
|
||||
-- ============================================
|
||||
-- 变更描述: 为用户表添加手机号字段
|
||||
-- 变更时间: 2024-01-15
|
||||
-- 影响版本: v1.1.0
|
||||
-- 影响表: user
|
||||
-- ============================================
|
||||
|
||||
-- 1. 添加字段
|
||||
ALTER TABLE `user`
|
||||
ADD COLUMN `phone` VARCHAR(20) COMMENT '手机号码';
|
||||
|
||||
-- 2. 添加索引
|
||||
ALTER TABLE `user`
|
||||
ADD INDEX `idx_phone` (`phone`);
|
||||
|
||||
-- 3. 更新现有数据(如有必要)
|
||||
UPDATE `user` SET `phone` = '' WHERE `phone` IS NULL;
|
||||
|
||||
-- 4. 验证变更
|
||||
SELECT COUNT(*) as phone_count FROM `user` WHERE `phone` IS NOT NULL;
|
||||
```
|
||||
|
||||
#### 回滚脚本模板
|
||||
```sql
|
||||
-- ============================================
|
||||
-- 回滚描述: 撤销用户表手机号字段添加
|
||||
-- 回滚时间: 20240115
|
||||
-- 原变更: 20240115_add_user_phone.sql
|
||||
-- ============================================
|
||||
|
||||
-- 1. 删除索引
|
||||
ALTER TABLE `user` DROP INDEX `idx_phone`;
|
||||
|
||||
-- 2. 删除字段
|
||||
ALTER TABLE `user` DROP COLUMN `phone`;
|
||||
|
||||
-- 3. 验证回滚
|
||||
SELECT COUNT(*) as remaining_indexes
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_NAME = 'user' AND COLUMN_NAME = 'phone';
|
||||
```
|
||||
|
||||
## 工作流程
|
||||
|
||||
### 完整同步流程
|
||||
```
|
||||
1. 实体类修改
|
||||
↓
|
||||
2. 生成差异报告
|
||||
↓
|
||||
3. 编写变更脚本
|
||||
↓
|
||||
4. 更新初始化脚本
|
||||
↓
|
||||
5. 同步设计文档
|
||||
↓
|
||||
6. 验证一致性
|
||||
↓
|
||||
7. 提交变更包
|
||||
```
|
||||
|
||||
### 自动化工具集成
|
||||
|
||||
#### 变更脚本生成器
|
||||
```python
|
||||
# generate-change-script.py
|
||||
import datetime
|
||||
import os
|
||||
|
||||
def create_change_script(table_name, changes, version):
|
||||
"""生成标准变更脚本"""
|
||||
today = datetime.date.today().strftime('%Y%m%d')
|
||||
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# 部署目录结构
|
||||
change_dir = "change/sql/upgrade"
|
||||
version_dir = f"{change_dir}/{version}"
|
||||
rollback_dir = f"{version_dir}/rollback"
|
||||
|
||||
# 创建目录
|
||||
os.makedirs(version_dir, exist_ok=True)
|
||||
os.makedirs(rollback_dir, exist_ok=True)
|
||||
|
||||
script_content = f"""-- ============================================
|
||||
-- 变更描述: {changes['description']}
|
||||
-- 变更时间: {timestamp}
|
||||
-- 影响版本: {version}
|
||||
-- 影响表: {table_name}
|
||||
-- ============================================
|
||||
|
||||
"""
|
||||
|
||||
# 添加具体的SQL变更
|
||||
for change_type, change_detail in changes.items():
|
||||
if change_type == 'add_columns':
|
||||
for column in change_detail:
|
||||
script_content += f"ALTER TABLE `{table_name}` ADD COLUMN {column};\n"
|
||||
|
||||
elif change_type == 'modify_columns':
|
||||
for column in change_detail:
|
||||
script_content += f"ALTER TABLE `{table_name}` MODIFY COLUMN {column};\n"
|
||||
|
||||
# 保存脚本
|
||||
filename = f"{today}_{changes['description'].replace(' ', '_').lower()}.sql"
|
||||
filepath = f"{version_dir}/{filename}"
|
||||
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(script_content)
|
||||
|
||||
return filepath
|
||||
```
|
||||
|
||||
#### 文档同步检查器
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# sync-documentation.sh
|
||||
|
||||
ENTITY_FILE=$1
|
||||
CHANGE_SCRIPT=$2
|
||||
|
||||
echo "=== 同步设计文档 ==="
|
||||
|
||||
# 提取变更信息
|
||||
TABLE_NAME=$(grep -o '@Table(name = "[^"]*")' "$ENTITY_FILE" | cut -d'"' -f2)
|
||||
CHANGE_DESC=$(basename "$CHANGE_SCRIPT" .sql | cut -d'_' -f2-)
|
||||
|
||||
# 更新数据库设计文档到change目录
|
||||
echo "更新数据库设计文档..."
|
||||
DOC_DIR="change/docs/database"
|
||||
mkdir -p "$DOC_DIR"
|
||||
|
||||
# 生成变更说明文档
|
||||
cat > "${DOC_DIR}/${TABLE_NAME}_change_${CHANGE_DESC}.md" << EOF
|
||||
# ${TABLE_NAME} 表结构变更说明
|
||||
|
||||
## 变更概述
|
||||
- 变更时间: $(date '+%Y-%m-%d')
|
||||
- 变更类型: 字段添加/修改/删除
|
||||
- 影响范围: ${TABLE_NAME} 表
|
||||
|
||||
## 详细变更
|
||||
$(cat "$CHANGE_SCRIPT")
|
||||
|
||||
## 业务影响
|
||||
- [ ] API接口适配
|
||||
- [ ] 前端页面调整
|
||||
- [ ] 数据迁移需求
|
||||
- [ ] 测试用例更新
|
||||
|
||||
## 验证清单
|
||||
- [ ] 开发环境验证
|
||||
- [ ] 测试环境验证
|
||||
- [ ] 生产环境预演
|
||||
EOF
|
||||
|
||||
echo "文档同步完成: ${DOC_DIR}/${TABLE_NAME}_change_${CHANGE_DESC}.md"
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 变更管理
|
||||
```
|
||||
版本分支 → 开发变更 → 生成脚本 → 文档同步 → 测试验证 → 合并发布
|
||||
```
|
||||
|
||||
### 2. 生产环境部署
|
||||
```bash
|
||||
# 生产环境变更部署流程
|
||||
1. 备份数据库
|
||||
2. 执行变更脚本
|
||||
3. 验证数据一致性
|
||||
4. 功能测试
|
||||
5. 监控观察
|
||||
6. 准备回滚方案
|
||||
```
|
||||
|
||||
### 3. 团队协作规范
|
||||
- 实体类修改必须附带变更脚本
|
||||
- 变更前必须进行影响评估
|
||||
- 多人协作时建立变更协调机制
|
||||
- 定期审查变更历史和文档同步情况
|
||||
|
||||
这个增强版的技能不仅确保实体类与数据库脚本的技术同步,还建立了完整的文档维护和生产环境变更管理流程。
|
||||
538
.qoder/skills/entity-db-sync/examples.md
Normal file
538
.qoder/skills/entity-db-sync/examples.md
Normal file
@ -0,0 +1,538 @@
|
||||
# 实体类与数据库脚本同步示例
|
||||
|
||||
## 基础同步示例
|
||||
|
||||
### 示例1: 简单用户实体
|
||||
|
||||
**Java实体类 (User.java):**
|
||||
```java
|
||||
package com.fundplatform.user.entity;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "user")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "username", length = 50, nullable = false, unique = true)
|
||||
private String username;
|
||||
|
||||
@Column(name = "email", length = 100)
|
||||
private String email;
|
||||
|
||||
@Column(name = "phone", length = 20)
|
||||
private String phone;
|
||||
|
||||
@Column(name = "is_active", columnDefinition = "TINYINT(1) DEFAULT 1")
|
||||
private Boolean active;
|
||||
|
||||
@Column(name = "created_time", updatable = false)
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
@Column(name = "updated_time")
|
||||
private LocalDateTime updatedTime;
|
||||
|
||||
// getters and setters...
|
||||
}
|
||||
```
|
||||
|
||||
**对应SQL脚本 (user.sql):**
|
||||
```sql
|
||||
CREATE TABLE `user` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
|
||||
`email` VARCHAR(100) COMMENT '邮箱地址',
|
||||
`phone` VARCHAR(20) COMMENT '手机号码',
|
||||
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否激活',
|
||||
`created_time` DATETIME COMMENT '创建时间',
|
||||
`updated_time` DATETIME COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_username` (`username`),
|
||||
KEY `idx_email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户基本信息表';
|
||||
```
|
||||
|
||||
### 示例2: 订单实体(复杂类型)
|
||||
|
||||
**Java实体类 (Order.java):**
|
||||
```java
|
||||
package com.fundplatform.order.entity;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "fund_order")
|
||||
public class Order {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long orderId;
|
||||
|
||||
@Column(name = "order_no", length = 32, nullable = false, unique = true)
|
||||
private String orderNo;
|
||||
|
||||
@Column(name = "customer_id", nullable = false)
|
||||
private Long customerId;
|
||||
|
||||
@Column(name = "project_id")
|
||||
private Long projectId;
|
||||
|
||||
@Column(name = "amount", precision = 15, scale = 2, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "order_date", nullable = false)
|
||||
private LocalDate orderDate;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "order_status", length = 20, nullable = false)
|
||||
private OrderStatus status;
|
||||
|
||||
@Column(name = "payment_method", length = 20)
|
||||
private String paymentMethod;
|
||||
|
||||
@Column(name = "remark", length = 500)
|
||||
private String remark;
|
||||
|
||||
// 枚举定义
|
||||
public enum OrderStatus {
|
||||
PENDING, CONFIRMED, PROCESSING, COMPLETED, CANCELLED
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**对应SQL脚本 (fund_order.sql):**
|
||||
```sql
|
||||
CREATE TABLE `fund_order` (
|
||||
`order_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '订单ID',
|
||||
`order_no` VARCHAR(32) NOT NULL COMMENT '订单编号',
|
||||
`customer_id` BIGINT NOT NULL COMMENT '客户ID',
|
||||
`project_id` BIGINT COMMENT '项目ID',
|
||||
`amount` DECIMAL(15,2) NOT NULL COMMENT '订单金额',
|
||||
`order_date` DATE NOT NULL COMMENT '下单日期',
|
||||
`order_status` VARCHAR(20) NOT NULL COMMENT '订单状态',
|
||||
`payment_method` VARCHAR(20) COMMENT '支付方式',
|
||||
`remark` VARCHAR(500) COMMENT '备注',
|
||||
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`order_id`),
|
||||
UNIQUE KEY `uk_order_no` (`order_no`),
|
||||
KEY `idx_customer_id` (`customer_id`),
|
||||
KEY `idx_order_date` (`order_date`),
|
||||
KEY `idx_order_status` (`order_status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='基金订单表';
|
||||
```
|
||||
|
||||
## 字段变更同步示例
|
||||
|
||||
### 场景1: 添加新字段
|
||||
|
||||
**原始实体类:**
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "product")
|
||||
public class Product {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Column(length = 100)
|
||||
private String name;
|
||||
|
||||
@Column(precision = 10, scale = 2)
|
||||
private BigDecimal price;
|
||||
}
|
||||
```
|
||||
|
||||
**修改后的实体类:**
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "product")
|
||||
public class Product {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Column(length = 100, nullable = false) // 添加非空约束
|
||||
private String name;
|
||||
|
||||
@Column(precision = 10, scale = 2, nullable = false) // 添加非空约束
|
||||
private BigDecimal price;
|
||||
|
||||
// 新增字段
|
||||
@Column(name = "category_id")
|
||||
private Long categoryId;
|
||||
|
||||
@Column(length = 500)
|
||||
private String description;
|
||||
|
||||
@Column(name = "is_available", columnDefinition = "TINYINT(1) DEFAULT 1")
|
||||
private Boolean available;
|
||||
}
|
||||
```
|
||||
|
||||
**变更脚本生成:**
|
||||
```bash
|
||||
# 使用变更脚本生成器
|
||||
python3 scripts/generate-change-scripts.py \
|
||||
--entity fund-product/src/main/java/com/fundplatform/product/entity/Product.java \
|
||||
--version v1.1.0 \
|
||||
--description "为产品表添加分类和描述字段"
|
||||
|
||||
# 生成的脚本文件位置(部署目录)
|
||||
deploy/sql/upgrade/v1.1.0/20240115_add_product_fields.sql
|
||||
deploy/sql/upgrade/v1.1.0/rollback/20240115_add_product_fields_rollback.sql
|
||||
```
|
||||
|
||||
**生成的正向变更脚本 (20240115_add_product_fields.sql):**
|
||||
```sql
|
||||
-- ============================================
|
||||
-- 变更描述: 为产品表添加分类和描述字段
|
||||
-- 变更时间: 2024-01-15 14:30:00
|
||||
-- 影响版本: v1.1.0
|
||||
-- 影响表: product
|
||||
-- ============================================
|
||||
|
||||
-- 1. 添加字段
|
||||
ALTER TABLE `product`
|
||||
ADD COLUMN `category_id` BIGINT COMMENT '分类ID',
|
||||
ADD COLUMN `description` VARCHAR(500) COMMENT '产品描述',
|
||||
ADD COLUMN `is_available` TINYINT(1) DEFAULT 1 COMMENT '是否可用';
|
||||
|
||||
-- 2. 添加索引
|
||||
ALTER TABLE `product`
|
||||
ADD INDEX `idx_category_id` (`category_id`);
|
||||
|
||||
-- 3. 验证变更
|
||||
SELECT COUNT(*) as new_columns FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = 'product' AND COLUMN_NAME IN ('category_id', 'description', 'is_available');
|
||||
```
|
||||
|
||||
**生成的回滚脚本 (20240115_add_product_fields_rollback.sql):**
|
||||
```sql
|
||||
-- ============================================
|
||||
-- 回滚描述: 撤销产品表字段添加变更
|
||||
-- 回滚时间: 2024-01-15 14:30:00
|
||||
-- 原版本: v1.1.0
|
||||
-- 影响表: product
|
||||
-- ============================================
|
||||
|
||||
-- 1. 删除索引
|
||||
ALTER TABLE `product` DROP INDEX `idx_category_id`;
|
||||
|
||||
-- 2. 删除字段
|
||||
ALTER TABLE `product`
|
||||
DROP COLUMN `category_id`,
|
||||
DROP COLUMN `description`,
|
||||
DROP COLUMN `is_available`;
|
||||
|
||||
-- 3. 验证回滚
|
||||
SELECT COUNT(*) as remaining_new_columns FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = 'product' AND COLUMN_NAME IN ('category_id', 'description', 'is_available');
|
||||
```
|
||||
|
||||
### 场景2: 字段类型变更
|
||||
|
||||
**实体类变更:**
|
||||
```java
|
||||
// 原始:String类型存储状态
|
||||
@Column(length = 20)
|
||||
private String status;
|
||||
|
||||
// 修改为:枚举类型
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(length = 20)
|
||||
private OrderStatus status;
|
||||
|
||||
public enum OrderStatus {
|
||||
DRAFT, SUBMITTED, APPROVED, REJECTED
|
||||
}
|
||||
```
|
||||
|
||||
**变更脚本:**
|
||||
```sql
|
||||
-- 20240120_modify_order_status_type.sql
|
||||
-- ============================================
|
||||
-- 变更描述: 修改订单状态字段类型为枚举
|
||||
-- 变更时间: 2024-01-20
|
||||
-- ============================================
|
||||
|
||||
-- 1. 添加新字段
|
||||
ALTER TABLE `order` ADD COLUMN `status_enum` VARCHAR(20) COMMENT '订单状态(枚举)';
|
||||
|
||||
-- 2. 数据迁移
|
||||
UPDATE `order` SET `status_enum` = `status` WHERE `status` IN ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED');
|
||||
|
||||
-- 3. 删除旧字段
|
||||
ALTER TABLE `order` DROP COLUMN `status`;
|
||||
|
||||
-- 4. 重命名新字段
|
||||
ALTER TABLE `order` CHANGE `status_enum` `status` VARCHAR(20) COMMENT '订单状态';
|
||||
|
||||
-- 5. 添加约束
|
||||
ALTER TABLE `order` ADD CONSTRAINT `chk_status_values`
|
||||
CHECK (`status` IN ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED'));
|
||||
```
|
||||
|
||||
## 文档同步示例
|
||||
|
||||
### 场景3: 设计文档更新
|
||||
|
||||
**更新数据库设计文档:**
|
||||
```markdown
|
||||
# product 表结构文档
|
||||
|
||||
## 表基本信息
|
||||
- **表名**: `product`
|
||||
- **描述**: 产品信息表
|
||||
- **引擎**: InnoDB
|
||||
- **字符集**: utf8mb4
|
||||
|
||||
## 字段定义
|
||||
| 字段名 | 类型 | 允许NULL | 默认值 | 描述 |
|
||||
|--------|------|----------|--------|------|
|
||||
| id | BIGINT | NO | AUTO_INCREMENT | 产品ID |
|
||||
| name | VARCHAR(100) | NO | | 产品名称 |
|
||||
| price | DECIMAL(10,2) | NO | | 产品价格 |
|
||||
| category_id | BIGINT | YES | NULL | 分类ID |
|
||||
| description | VARCHAR(500) | YES | NULL | 产品描述 |
|
||||
| is_available | TINYINT(1) | YES | 1 | 是否可用 |
|
||||
| created_time | DATETIME | YES | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_time | DATETIME | YES | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
## 索引信息
|
||||
| 索引名 | 类型 | 字段 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| PRIMARY | PRIMARY | id | 主键索引 |
|
||||
| idx_category_id | NORMAL | category_id | 分类索引 |
|
||||
|
||||
## 变更历史
|
||||
| 日期 | 版本 | 变更描述 | 变更人 |
|
||||
|------|------|----------|--------|
|
||||
| 2024-01-15 | v1.1.0 | 添加分类ID、产品描述和可用状态字段 | Zhang San |
|
||||
| 2024-01-10 | v1.0.0 | 初始版本 | Li Si |
|
||||
```
|
||||
|
||||
**API文档更新:**
|
||||
```markdown
|
||||
# 产品管理API接口
|
||||
|
||||
## GET /api/products
|
||||
获取产品列表
|
||||
|
||||
### 请求参数
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| categoryId | Long | 否 | 分类产品筛选 |
|
||||
| available | Boolean | 否 | 可用性筛选 |
|
||||
|
||||
### 响应示例
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"records": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "基金产品A",
|
||||
"price": 100.50,
|
||||
"categoryId": 1,
|
||||
"description": "这是一款优质基金产品",
|
||||
"available": true,
|
||||
"createdTime": "2024-01-15T10:30:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## 生产环境部署示例
|
||||
|
||||
### 场景4: 生产环境变更流程
|
||||
|
||||
**变更申请表:**
|
||||
```markdown
|
||||
# 数据库变更申请
|
||||
|
||||
## 基本信息
|
||||
- **申请人**: 张三
|
||||
- **申请时间**: 2024-01-15 15:00
|
||||
- **变更类型**: 字段添加
|
||||
- **影响系统**: 产品管理系统
|
||||
- **预计 downtime**: 5分钟
|
||||
|
||||
## 变更详情
|
||||
- **变更SQL**: src/main/resources/sql/upgrade/v1.1.0/20240115_add_product_fields.sql
|
||||
- **回滚SQL**: src/main/resources/sql/upgrade/v1.1.0/rollback/20240115_add_product_fields_rollback.sql
|
||||
- **验证SQL**: src/main/resources/sql/upgrade/v1.1.0/verify/20240115_add_product_fields_verify.sql
|
||||
|
||||
## 风险评估
|
||||
- [x] 数据备份已完成
|
||||
- [x] 回滚方案已准备
|
||||
- [x] 测试环境验证通过
|
||||
- [x] 监控告警已设置
|
||||
|
||||
## 执行计划
|
||||
1. 20:00 - 开始变更
|
||||
2. 20:01 - 执行备份
|
||||
3. 20:02 - 执行变更脚本
|
||||
4. 20:03 - 执行验证脚本
|
||||
5. 20:04 - 功能测试
|
||||
6. 20:05 - 变更完成
|
||||
```
|
||||
|
||||
**生产环境执行脚本:**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# production-deploy.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== 生产环境数据库变更部署 ==="
|
||||
echo "变更版本: v1.1.0"
|
||||
echo "执行时间: $(date)"
|
||||
echo ""
|
||||
|
||||
# 1. 环境检查
|
||||
echo "1. 环境检查..."
|
||||
if [ -z "$DB_HOST" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then
|
||||
echo "❌ 数据库连接信息不完整"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. 数据库备份
|
||||
echo "2. 执行数据库备份..."
|
||||
BACKUP_FILE="/backup/proddb_$(date +%Y%m%d_%H%M%S).sql"
|
||||
mysqldump -h$DB_HOST -u$DB_USER -p$DB_PASSWORD fund_platform > $BACKUP_FILE
|
||||
echo "✓ 备份完成: $BACKUP_FILE"
|
||||
|
||||
# 3. 执行变更(使用部署目录)
|
||||
echo "3. 执行变更脚本..."
|
||||
mysql -h$DB_HOST -u$DB_USER -p$DB_PASSWORD fund_platform < \
|
||||
deploy/sql/upgrade/v1.1.0/20240115_add_product_fields.sql
|
||||
|
||||
# 4. 验证变更
|
||||
echo "4. 验证变更结果..."
|
||||
mysql -h$DB_HOST -u$DB_USER -p$DB_PASSWORD fund_platform < \
|
||||
deploy/sql/upgrade/v1.1.0/verify/20240115_add_product_fields_verify.sql
|
||||
|
||||
# 5. 记录变更日志
|
||||
echo "5. 记录变更日志..."
|
||||
mysql -h$DB_HOST -u$DB_USER -p$DB_PASSWORD fund_platform << EOF
|
||||
INSERT INTO db_changelog (version, script_name, execute_time, operator, environment)
|
||||
VALUES ('v1.1.0', '20240115_add_product_fields.sql', NOW(), '$USER', 'production');
|
||||
EOF
|
||||
|
||||
echo "✓ 变更部署完成"
|
||||
echo "请进行业务功能验证"
|
||||
```
|
||||
|
||||
## 自动化验证示例
|
||||
|
||||
### 验证脚本使用
|
||||
|
||||
**单个实体验证:**
|
||||
```bash
|
||||
# 验证用户实体与数据库脚本同步性
|
||||
python3 scripts/validate-entity-db-sync.py \
|
||||
fund-user/src/main/java/com/fundplatform/user/entity/User.java \
|
||||
fund-user/src/main/resources/sql/init/user.sql
|
||||
|
||||
# 输出示例:
|
||||
# ✅ 字段一致: id -> id (BIGINT)
|
||||
# ✅ 字段一致: username -> username (VARCHAR(50))
|
||||
# ⚠️ 新增字段: phone (数据库中缺失)
|
||||
# ❌ 类型不匹配: email长度应为100,当前为50
|
||||
```
|
||||
|
||||
**批量验证:**
|
||||
```bash
|
||||
# 验证所有模块的实体同步性
|
||||
./scripts/batch-validate-sync.sh
|
||||
|
||||
# 输出示例:
|
||||
# === 批量验证实体类与数据库脚本同步 ===
|
||||
# 检查: User -> user
|
||||
# ✅ 实体类与数据库脚本同步一致
|
||||
#
|
||||
# 检查: Order -> fund_order
|
||||
# ⚠️ 发现3个不一致项
|
||||
# ❌ 字段email长度不匹配
|
||||
# ⚠️ 缺少字段phone
|
||||
# ⚠️ 缺少字段description
|
||||
#
|
||||
# === 检查完成 ===
|
||||
# 错误: 1
|
||||
# 警告: 2
|
||||
```
|
||||
|
||||
### CI集成配置
|
||||
|
||||
**GitHub Actions配置:**
|
||||
```yaml
|
||||
name: Entity-DB Sync Check
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
sync-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install mysql-connector-python
|
||||
|
||||
- name: Run sync validation
|
||||
run: |
|
||||
chmod +x scripts/batch-validate-sync.sh
|
||||
./scripts/batch-validate-sync.sh
|
||||
|
||||
- name: Generate change scripts
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
python3 scripts/generate-change-scripts.py --auto-generate
|
||||
|
||||
- name: Upload artifacts
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sync-report
|
||||
path: sync-report.txt
|
||||
```
|
||||
|
||||
**Git Pre-commit Hook:**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# .git/hooks/pre-commit
|
||||
|
||||
# 检查是否有实体类修改
|
||||
if git diff --cached --name-only | grep -q "entity/.*\.java"; then
|
||||
echo "检测到实体类修改,运行同步检查..."
|
||||
|
||||
# 执行验证
|
||||
if ! ./scripts/batch-validate-sync.sh; then
|
||||
echo "❌ 实体类与数据库脚本不同步,请修复后再提交"
|
||||
echo "提示:运行 'python3 scripts/generate-sql-from-entity.py <Entity.java>' 生成SQL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 自动生成变更脚本
|
||||
echo "生成变更脚本..."
|
||||
python3 scripts/generate-change-scripts.py --auto-generate
|
||||
|
||||
echo "✅ 同步检查通过"
|
||||
fi
|
||||
```
|
||||
|
||||
这些示例展示了从简单到复杂的各种同步场景,包括变更脚本生成、文档同步和生产环境部署的完整流程。
|
||||
545
.qoder/skills/entity-db-sync/reference.md
Normal file
545
.qoder/skills/entity-db-sync/reference.md
Normal file
@ -0,0 +1,545 @@
|
||||
# 实体类与数据库脚本同步参考手册
|
||||
|
||||
## 详细映射规则
|
||||
|
||||
### 数据类型映射表
|
||||
|
||||
#### 基本数据类型
|
||||
| Java类型 | MySQL类型 | 注解示例 | 说明 |
|
||||
|----------|-----------|----------|------|
|
||||
| `String` | `VARCHAR(N)` | `@Column(length=50)` | 默认长度255 |
|
||||
| `String` | `TEXT` | `@Column(length=2000)` | 长文本 |
|
||||
| `String` | `LONGTEXT` | `@Column(length=10000)` | 超长文本 |
|
||||
| `Integer`/`int` | `INT` | `@Column` | 32位整数 |
|
||||
| `Long`/`long` | `BIGINT` | `@Column` | 64位整数 |
|
||||
| `Short`/`short` | `SMALLINT` | `@Column` | 16位整数 |
|
||||
| `Byte`/`byte` | `TINYINT` | `@Column` | 8位整数 |
|
||||
| `Float`/`float` | `FLOAT` | `@Column` | 单精度浮点 |
|
||||
| `Double`/`double` | `DOUBLE` | `@Column` | 双精度浮点 |
|
||||
| `Boolean`/`boolean` | `TINYINT(1)` | `@Column` | 布尔值 |
|
||||
| `Character`/`char` | `CHAR(1)` | `@Column` | 单字符 |
|
||||
|
||||
#### 数值类型
|
||||
| Java类型 | MySQL类型 | 注解示例 | 说明 |
|
||||
|----------|-----------|----------|------|
|
||||
| `BigDecimal` | `DECIMAL(M,D)` | `@Column(precision=10, scale=2)` | 精确小数 |
|
||||
| `BigInteger` | `DECIMAL(M,0)` | `@Column(precision=20)` | 大整数 |
|
||||
|
||||
#### 日期时间类型
|
||||
| Java类型 | MySQL类型 | 注解示例 | 说明 |
|
||||
|----------|-----------|----------|------|
|
||||
| `LocalDate` | `DATE` | `@Column` | 日期 |
|
||||
| `LocalTime` | `TIME` | `@Column` | 时间 |
|
||||
| `LocalDateTime` | `DATETIME` | `@Column` | 日期时间 |
|
||||
| `Instant` | `TIMESTAMP` | `@Column` | 时间戳 |
|
||||
| `Year` | `YEAR` | `@Column` | 年份 |
|
||||
|
||||
#### 枚举类型
|
||||
```java
|
||||
// 方式1: 字符串存储
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(length = 20)
|
||||
private UserType userType;
|
||||
|
||||
// 方式2: 整数存储
|
||||
@Enumerated(EnumType.ORDINAL)
|
||||
@Column
|
||||
private Status status;
|
||||
```
|
||||
|
||||
#### 集合类型
|
||||
```java
|
||||
// JSON格式存储
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
@Column(columnDefinition = "JSON")
|
||||
private List<String> tags;
|
||||
|
||||
// 或者使用单独的关联表
|
||||
@ElementCollection
|
||||
@CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"))
|
||||
private Set<String> roles;
|
||||
```
|
||||
|
||||
### 注解详细说明
|
||||
|
||||
#### @Column注解参数
|
||||
```java
|
||||
@Column(
|
||||
name = "column_name", // 数据库列名
|
||||
length = 255, // VARCHAR长度
|
||||
nullable = true, // 是否允许NULL
|
||||
unique = false, // 是否唯一
|
||||
precision = 10, // 数字总位数
|
||||
scale = 2, // 小数位数
|
||||
columnDefinition = "TEXT" // 自定义列定义
|
||||
)
|
||||
```
|
||||
|
||||
#### @Id相关注解
|
||||
```java
|
||||
// 自增主键
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
// UUID主键
|
||||
@Id
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||
@Column(name = "id", length = 36)
|
||||
private String id;
|
||||
|
||||
// 复合主键
|
||||
@EmbeddedId
|
||||
private UserRoleId id;
|
||||
```
|
||||
|
||||
#### 时间戳注解
|
||||
```java
|
||||
// 创建时间自动设置
|
||||
@CreationTimestamp
|
||||
@Column(name = "created_time", updatable = false)
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
// 更新时间自动设置
|
||||
@UpdateTimestamp
|
||||
@Column(name = "updated_time")
|
||||
private LocalDateTime updatedTime;
|
||||
```
|
||||
|
||||
## 变更管理工具
|
||||
|
||||
### 变更脚本生成器
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# generate-change-scripts.py
|
||||
|
||||
import os
|
||||
import re
|
||||
import datetime
|
||||
from typing import Dict, List
|
||||
|
||||
class ChangeScriptGenerator:
|
||||
def __init__(self, project_root: str):
|
||||
self.project_root = project_root
|
||||
# 部署目录结构:与开发代码分离
|
||||
self.deploy_dir = os.path.join(project_root, "deploy", "sql")
|
||||
self.upgrade_dir = os.path.join(self.deploy_dir, "upgrade")
|
||||
self.init_dir = os.path.join(self.deploy_dir, "init")
|
||||
|
||||
def create_version_directory(self, version: str) -> str:
|
||||
"""创建版本目录"""
|
||||
version_dir = os.path.join(self.upgrade_dir, version)
|
||||
os.makedirs(version_dir, exist_ok=True)
|
||||
os.makedirs(os.path.join(version_dir, "rollback"), exist_ok=True)
|
||||
return version_dir
|
||||
|
||||
def generate_alter_script(self, table_name: str, changes: Dict, version: str) -> str:
|
||||
"""生成ALTER TABLE脚本"""
|
||||
today = datetime.date.today().strftime('%Y%m%d')
|
||||
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# 生成正向变更脚本
|
||||
forward_content = f"""-- ============================================
|
||||
-- 变更描述: {changes.get('description', '数据库结构变更')}
|
||||
-- 变更时间: {timestamp}
|
||||
-- 影响版本: {version}
|
||||
-- 影响表: {table_name}
|
||||
-- ============================================
|
||||
|
||||
"""
|
||||
|
||||
# 添加字段变更
|
||||
if 'add_columns' in changes:
|
||||
forward_content += "-- 1. 添加字段\n"
|
||||
for column_def in changes['add_columns']:
|
||||
forward_content += f"ALTER TABLE `{table_name}` ADD COLUMN {column_def};\n"
|
||||
forward_content += "\n"
|
||||
|
||||
if 'modify_columns' in changes:
|
||||
forward_content += "-- 2. 修改字段\n"
|
||||
for column_def in changes['modify_columns']:
|
||||
forward_content += f"ALTER TABLE `{table_name}` MODIFY COLUMN {column_def};\n"
|
||||
forward_content += "\n"
|
||||
|
||||
if 'drop_columns' in changes:
|
||||
forward_content += "-- 3. 删除字段\n"
|
||||
for column_name in changes['drop_columns']:
|
||||
forward_content += f"ALTER TABLE `{table_name}` DROP COLUMN `{column_name}`;\n"
|
||||
forward_content += "\n"
|
||||
|
||||
# 添加索引变更
|
||||
if 'add_indexes' in changes:
|
||||
forward_content += "-- 4. 添加索引\n"
|
||||
for index_def in changes['add_indexes']:
|
||||
forward_content += f"ALTER TABLE `{table_name}` ADD {index_def};\n"
|
||||
forward_content += "\n"
|
||||
|
||||
# 生成回滚脚本
|
||||
rollback_content = self.generate_rollback_script(table_name, changes, timestamp, version)
|
||||
|
||||
# 保存脚本文件
|
||||
version_dir = self.create_version_directory(version)
|
||||
forward_filename = f"{today}_{self.sanitize_filename(changes.get('description', 'change'))}.sql"
|
||||
rollback_filename = f"{today}_{self.sanitize_filename(changes.get('description', 'change'))}_rollback.sql"
|
||||
|
||||
forward_path = os.path.join(version_dir, forward_filename)
|
||||
rollback_path = os.path.join(version_dir, "rollback", rollback_filename)
|
||||
|
||||
with open(forward_path, 'w', encoding='utf-8') as f:
|
||||
f.write(forward_content)
|
||||
|
||||
with open(rollback_path, 'w', encoding='utf-8') as f:
|
||||
f.write(rollback_content)
|
||||
|
||||
return forward_path
|
||||
|
||||
def generate_rollback_script(self, table_name: str, changes: Dict, timestamp: str, version: str) -> str:
|
||||
"""生成回滚脚本"""
|
||||
rollback_content = f"""-- ============================================
|
||||
-- 回滚描述: 撤销 {changes.get('description', '数据库变更')}
|
||||
-- 回滚时间: {timestamp}
|
||||
-- 原版本: {version}
|
||||
-- 影响表: {table_name}
|
||||
-- ============================================
|
||||
|
||||
"""
|
||||
|
||||
# 删除索引(逆序)
|
||||
if 'add_indexes' in changes:
|
||||
rollback_content += "-- 1. 删除新增的索引\n"
|
||||
for index_def in reversed(changes['add_indexes']):
|
||||
index_name = self.extract_index_name(index_def)
|
||||
if index_name:
|
||||
rollback_content += f"ALTER TABLE `{table_name}` DROP INDEX `{index_name}`;\n"
|
||||
rollback_content += "\n"
|
||||
|
||||
# 删除字段(逆序)
|
||||
if 'add_columns' in changes:
|
||||
rollback_content += "-- 2. 删除新增的字段\n"
|
||||
for column_def in reversed(changes['add_columns']):
|
||||
column_name = self.extract_column_name(column_def)
|
||||
if column_name:
|
||||
rollback_content += f"ALTER TABLE `{table_name}` DROP COLUMN `{column_name}`;\n"
|
||||
rollback_content += "\n"
|
||||
|
||||
# 恢复修改的字段
|
||||
if 'modify_columns' in changes:
|
||||
rollback_content += "-- 3. 恢复修改的字段\n"
|
||||
# 这里需要保存原始定义才能准确回滚
|
||||
rollback_content += "-- TODO: 需要手动添加原始字段定义\n"
|
||||
rollback_content += "\n"
|
||||
|
||||
return rollback_content
|
||||
|
||||
def sanitize_filename(self, text: str) -> str:
|
||||
"""清理文件名"""
|
||||
return re.sub(r'[^\w\-_]', '_', text.lower())
|
||||
|
||||
def extract_column_name(self, column_def: str) -> str:
|
||||
"""从列定义中提取列名"""
|
||||
match = re.search(r'`([^`]+)`', column_def)
|
||||
return match.group(1) if match else ""
|
||||
|
||||
def extract_index_name(self, index_def: str) -> str:
|
||||
"""从索引定义中提取索引名"""
|
||||
match = re.search(r'`([^`]+)`\s*\(', index_def)
|
||||
return match.group(1) if match else ""
|
||||
|
||||
# 使用示例
|
||||
if __name__ == "__main__":
|
||||
generator = ChangeScriptGenerator("/path/to/project")
|
||||
|
||||
changes = {
|
||||
'description': '为用户表添加手机号字段',
|
||||
'add_columns': [
|
||||
'`phone` VARCHAR(20) COMMENT \'手机号码\'',
|
||||
'`wechat_id` VARCHAR(50) COMMENT \'微信ID\''
|
||||
],
|
||||
'add_indexes': [
|
||||
'INDEX `idx_phone` (`phone`)',
|
||||
'INDEX `idx_wechat_id` (`wechat_id`)'
|
||||
]
|
||||
}
|
||||
|
||||
script_path = generator.generate_alter_script('user', changes, 'v1.1.0')
|
||||
print(f"生成变更脚本: {script_path}")
|
||||
```
|
||||
|
||||
### 文档同步工具
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# sync-documentation.py
|
||||
|
||||
import os
|
||||
import json
|
||||
from typing import Dict, List
|
||||
|
||||
class DocumentationSync:
|
||||
def __init__(self, project_root: str):
|
||||
self.project_root = project_root
|
||||
self.docs_dir = os.path.join(project_root, "docs")
|
||||
self.db_docs_dir = os.path.join(self.docs_dir, "database")
|
||||
|
||||
def update_table_documentation(self, table_name: str, entity_info: Dict, changes: Dict):
|
||||
"""更新表结构文档"""
|
||||
doc_file = os.path.join(self.db_docs_dir, f"{table_name}.md")
|
||||
|
||||
# 读取现有文档或创建新文档
|
||||
if os.path.exists(doc_file):
|
||||
with open(doc_file, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
else:
|
||||
content = self.create_table_template(table_name)
|
||||
|
||||
# 更新字段信息
|
||||
content = self.update_fields_section(content, entity_info['fields'])
|
||||
|
||||
# 添加变更历史
|
||||
content = self.add_change_history(content, changes)
|
||||
|
||||
# 保存更新后的文档
|
||||
os.makedirs(os.path.dirname(doc_file), exist_ok=True)
|
||||
with open(doc_file, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
def create_table_template(self, table_name: str) -> str:
|
||||
"""创建表文档模板"""
|
||||
return f"""# {table_name} 表结构文档
|
||||
|
||||
## 表基本信息
|
||||
- **表名**: `{table_name}`
|
||||
- **描述**:
|
||||
- **引擎**: InnoDB
|
||||
- **字符集**: utf8mb4
|
||||
|
||||
## 字段定义
|
||||
| 字段名 | 类型 | 允许NULL | 默认值 | 描述 |
|
||||
|--------|------|----------|--------|------|
|
||||
| id | BIGINT | NO | AUTO_INCREMENT | 主键ID |
|
||||
|
||||
## 索引信息
|
||||
| 索引名 | 类型 | 字段 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| PRIMARY | PRIMARY | id | 主键索引 |
|
||||
|
||||
## 变更历史
|
||||
| 日期 | 版本 | 变更描述 | 变更人 |
|
||||
|------|------|----------|--------|
|
||||
"""
|
||||
|
||||
def update_fields_section(self, content: str, fields: List[Dict]) -> str:
|
||||
"""更新字段定义部分"""
|
||||
# 找到字段定义表格的位置并替换
|
||||
lines = content.split('\n')
|
||||
in_fields_section = False
|
||||
field_lines = []
|
||||
|
||||
for line in lines:
|
||||
if line.strip() == '## 字段定义':
|
||||
in_fields_section = True
|
||||
field_lines.append(line)
|
||||
continue
|
||||
|
||||
if in_fields_section and line.startswith('|') and '字段名' in line:
|
||||
# 保留表头
|
||||
field_lines.append(line)
|
||||
continue
|
||||
|
||||
if in_fields_section and line.startswith('|----'):
|
||||
# 保留分隔线
|
||||
field_lines.append(line)
|
||||
continue
|
||||
|
||||
if in_fields_section and line.startswith('|') and line.count('|') >= 5:
|
||||
# 跳过旧的字段行
|
||||
continue
|
||||
|
||||
if in_fields_section and not line.strip():
|
||||
# 结束字段部分
|
||||
in_fields_section = False
|
||||
# 添加新的字段定义
|
||||
for field in fields:
|
||||
field_lines.append(self.format_field_row(field))
|
||||
field_lines.append('')
|
||||
|
||||
field_lines.append(line)
|
||||
|
||||
return '\n'.join(field_lines)
|
||||
|
||||
def format_field_row(self, field: Dict) -> str:
|
||||
"""格式化字段行"""
|
||||
nullable = 'YES' if field.get('nullable', True) else 'NO'
|
||||
default_val = field.get('default', '')
|
||||
description = field.get('comment', '')
|
||||
|
||||
return f"| {field['name']} | {field['type']} | {nullable} | {default_val} | {description} |"
|
||||
|
||||
def add_change_history(self, content: str, changes: Dict) -> str:
|
||||
"""添加变更历史"""
|
||||
import datetime
|
||||
today = datetime.date.today().strftime('%Y-%m-%d')
|
||||
|
||||
change_line = f"| {today} | {changes.get('version', 'unknown')} | {changes.get('description', '')} | {changes.get('author', 'system')} |"
|
||||
|
||||
# 在变更历史部分添加新行
|
||||
lines = content.split('\n')
|
||||
for i, line in enumerate(lines):
|
||||
if '| 日期 | 版本 | 变更描述 | 变更人 |' in line:
|
||||
# 在表头后插入新行
|
||||
lines.insert(i + 2, change_line)
|
||||
break
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
# 配置文件示例
|
||||
CONFIG = {
|
||||
"documentation": {
|
||||
"enabled": True,
|
||||
"output_dir": "docs/database",
|
||||
"auto_update": True
|
||||
},
|
||||
"change_scripts": {
|
||||
"upgrade_dir": "src/main/resources/sql/upgrade",
|
||||
"version_pattern": "v{major}.{minor}.{patch}",
|
||||
"naming_convention": "{date}_{description}.sql"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 生产环境部署规范
|
||||
|
||||
### 变更脚本目录结构
|
||||
```
|
||||
project/
|
||||
├── deploy/ # 部署相关文件(与开发代码分离)
|
||||
│ └── sql/
|
||||
│ ├── init/ # 初始部署脚本
|
||||
│ │ ├── v1.0.0/
|
||||
│ │ │ ├── 01_create_tables.sql
|
||||
│ │ │ ├── 02_insert_init_data.sql
|
||||
│ │ │ └── README.md
|
||||
│ │ └── v1.1.0/
|
||||
│ │ └── 01_upgrade_v1.1.0.sql
|
||||
│ └── upgrade/ # 增量变更脚本
|
||||
│ ├── v1.1.0/
|
||||
│ │ ├── 20240115_add_user_phone.sql
|
||||
│ │ ├── 20240115_add_user_phone_rollback.sql
|
||||
│ │ └── changelog.md
|
||||
│ ├── v1.2.0/
|
||||
│ │ ├── 20240201_modify_order_amount.sql
|
||||
│ │ ├── 20240201_modify_order_amount_rollback.sql
|
||||
│ │ └── changelog.md
|
||||
│ └── current/ # 当前开发中的变更
|
||||
│ └── draft_changes/
|
||||
└── src/main/resources/ # 开发代码目录(保持独立)
|
||||
```
|
||||
|
||||
# 生产环境部署规范
|
||||
|
||||
### 变更脚本执行流程
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# deploy-database-changes.sh
|
||||
|
||||
ENVIRONMENT=${1:-"test"}
|
||||
VERSION=${2:-"latest"}
|
||||
BACKUP_FIRST=${3:-"true"}
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="${SCRIPT_DIR}/../.."
|
||||
# 使用部署目录
|
||||
DEPLOY_SQL_DIR="${PROJECT_ROOT}/deploy/sql"
|
||||
|
||||
echo "=== 数据库变更部署 ==="
|
||||
echo "环境: ${ENVIRONMENT}"
|
||||
echo "版本: ${VERSION}"
|
||||
echo "备份: ${BACKUP_FIRST}"
|
||||
echo ""
|
||||
|
||||
# 1. 数据库备份
|
||||
if [ "${BACKUP_FIRST}" = "true" ]; then
|
||||
echo "1. 执行数据库备份..."
|
||||
BACKUP_FILE="/tmp/db_backup_$(date +%Y%m%d_%H%M%S).sql"
|
||||
mysqldump -h${DB_HOST} -u${DB_USER} -p${DB_PASSWORD} ${DB_NAME} > "${BACKUP_FILE}"
|
||||
echo "备份完成: ${BACKUP_FILE}"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# 2. 确定要执行的脚本
|
||||
if [ "${VERSION}" = "latest" ]; then
|
||||
# 执行所有未应用的变更
|
||||
CHANGE_SCRIPTS=$(find "${DEPLOY_SQL_DIR}/upgrade" -name "*.sql" ! -name "*_rollback.sql" | sort)
|
||||
else
|
||||
# 执行指定版本的变更
|
||||
CHANGE_SCRIPTS=$(find "${DEPLOY_SQL_DIR}/upgrade/${VERSION}" -name "*.sql" ! -name "*_rollback.sql" | sort)
|
||||
fi
|
||||
```
|
||||
# 3. 执行变更脚本
|
||||
echo "2. 执行变更脚本..."
|
||||
for script in ${CHANGE_SCRIPTS}; do
|
||||
echo "执行: $(basename ${script})"
|
||||
|
||||
# 记录执行日志
|
||||
mysql -h${DB_HOST} -u${DB_USER} -p${DB_PASSWORD} ${DB_NAME} < "${script}"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✓ 执行成功"
|
||||
# 记录到变更历史表
|
||||
echo "INSERT INTO db_changelog (script_name, execute_time, environment) VALUES ('$(basename ${script})', NOW(), '${ENVIRONMENT}');" | \
|
||||
mysql -h${DB_HOST} -u${DB_USER} -p${DB_PASSWORD} ${DB_NAME}
|
||||
else
|
||||
echo "✗ 执行失败"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# 4. 验证变更
|
||||
echo ""
|
||||
echo "3. 验证变更结果..."
|
||||
# 执行验证脚本
|
||||
VERIFY_SCRIPT="${DEPLOY_SQL_DIR}/upgrade/${VERSION}/verify_changes.sql"
|
||||
if [ -f "${VERIFY_SCRIPT}" ]; then
|
||||
mysql -h${DB_HOST} -u${DB_USER} -p${DB_PASSWORD} ${DB_NAME} < "${VERIFY_SCRIPT}"
|
||||
fi
|
||||
|
||||
echo "数据库变更部署完成!"
|
||||
```
|
||||
|
||||
### 变更风险评估模板
|
||||
```markdown
|
||||
# 数据库变更风险评估表
|
||||
|
||||
## 基本信息
|
||||
- **变更编号**: DB-20240115-001
|
||||
- **变更类型**: 字段添加/修改/删除
|
||||
- **影响表**: user
|
||||
- **预计执行时间**: 5分钟
|
||||
- **回滚时间**: 2分钟
|
||||
|
||||
## 影响评估
|
||||
### 业务影响
|
||||
- [ ] 用户注册/登录功能
|
||||
- [ ] 数据查询性能
|
||||
- [ ] 报表统计准确性
|
||||
- [ ] 第三方系统对接
|
||||
|
||||
### 技术风险
|
||||
- [ ] 数据一致性风险
|
||||
- [ ] 性能下降风险
|
||||
- [ ] 锁表时间过长
|
||||
- [ ] 空间不足风险
|
||||
|
||||
## 预防措施
|
||||
- [ ] 执行前完整备份
|
||||
- [ ] 低峰期执行变更
|
||||
- [ ] 准备回滚方案
|
||||
- [ ] 安排专人监控
|
||||
|
||||
## 应急预案
|
||||
- **回滚步骤**: [详细回滚操作步骤]
|
||||
- **联系人员**: [紧急联系人列表]
|
||||
- **监控指标**: [关键监控项]
|
||||
```
|
||||
|
||||
这份参考手册提供了完整的实体类与数据库脚本同步的技术细节、工具脚本和生产环境部署规范。
|
||||
441
.qoder/skills/maven-assembly/SKILL.md
Normal file
441
.qoder/skills/maven-assembly/SKILL.md
Normal file
@ -0,0 +1,441 @@
|
||||
---
|
||||
name: maven-assembly
|
||||
description: 针对资金服务平台项目的Maven Assembly打包技能,专门处理env.properties统一配置和service.properties个性化配置的合并打包,生成包含bin/lib/conf目录结构的tar.gz部署包,支持自动化的构建脚本。使用场景:当需要生成或修改项目的Assembly配置文件、创建部署包、处理配置文件合并、进行多服务打包时自动触发。
|
||||
---
|
||||
|
||||
# 资金服务平台 Maven Assembly 打包技能
|
||||
|
||||
## 触发条件
|
||||
|
||||
当出现以下情况时,自动应用此技能:
|
||||
|
||||
1. **配置文件管理相关**:
|
||||
- 需要创建或修改 `env.properties` 统一配置文件
|
||||
- 需要创建或修改各服务的 `service.properties` 个性化配置
|
||||
- 需要处理配置文件的合并和加载顺序
|
||||
|
||||
2. **Assembly配置相关**:
|
||||
- 需要生成项目的 `assembly.xml` 配置文件
|
||||
- 需要配置 Maven Assembly 插件
|
||||
- 需要设置打包目录结构和文件包含规则
|
||||
|
||||
3. **构建打包相关**:
|
||||
- 需要创建或修改批量构建脚本
|
||||
- 需要生成包含 bin/lib/conf 目录结构的部署包
|
||||
- 需要处理多服务模块的统一打包
|
||||
|
||||
4. **部署验证相关**:
|
||||
- 需要验证部署包的完整性和正确性
|
||||
- 需要检查配置文件的必需参数
|
||||
- 需要测试启动脚本的配置加载机制
|
||||
|
||||
5. **部署目录管理相关**:
|
||||
- 需要将所有打包产物统一存储在项目根目录的 `deploy/` 目录下
|
||||
- 需要维护部署包的版本管理和清理机制
|
||||
- 需要确保部署目录与开发代码的物理分离
|
||||
|
||||
## 项目架构概述
|
||||
|
||||
本技能专为资金服务平台定制,采用**统一配置 + 个性化配置**分离架构,并实现**开发代码与部署产物物理分离**:
|
||||
|
||||
```
|
||||
fundplatform/
|
||||
├── deploy/ # 部署产物目录(所有打包文件统一存放)
|
||||
│ ├── fund-gateway.tar.gz
|
||||
│ ├── fund-sys.tar.gz
|
||||
│ ├── fund-cust.tar.gz
|
||||
│ └── ... 其他服务部署包
|
||||
├── scripts/ # 统一脚本和配置目录
|
||||
│ ├── env.properties # 统一配置(所有服务共用)
|
||||
│ ├── start.sh # 启动脚本
|
||||
│ ├── stop.sh # 停止脚本
|
||||
│ └── build-services.sh # 自动构建脚本
|
||||
├── fund-sys/ # 服务源代码目录
|
||||
│ └── src/main/resources/
|
||||
│ └── service.properties # 个性化配置(每服务独立)
|
||||
├── fund-gateway/
|
||||
│ └── src/main/resources/
|
||||
│ └── service.properties
|
||||
└── ... 其他服务模块
|
||||
```
|
||||
|
||||
**核心实践原则**:
|
||||
- 所有部署打包文件统一存储在项目根目录的 `deploy/` 目录下
|
||||
- 开发代码与部署产物物理分离,便于版本管理和CI/CD集成
|
||||
- 通过 `services-build.sh` 脚本自动收集各服务构建产物到统一部署目录
|
||||
|
||||
## 配置文件管理
|
||||
|
||||
### 统一配置 (env.properties)
|
||||
**位置**: `scripts/env.properties`
|
||||
**用途**: 所有服务共用的基础配置
|
||||
**包含内容**:
|
||||
- Nacos配置
|
||||
- Redis配置
|
||||
- 数据库连接池配置
|
||||
- 日志配置
|
||||
- 腾讯云COS配置
|
||||
- 多租户路由配置
|
||||
|
||||
### 个性化配置 (service.properties)
|
||||
**位置**: 各服务 `src/main/resources/service.properties`
|
||||
**用途**: 服务独立的个性化参数
|
||||
**必须包含**:
|
||||
```properties
|
||||
APP_NAME=fund-sys # 服务名称
|
||||
MAIN_CLASS=com.xxx.App # 主启动类
|
||||
INSTANCE_NAME= # 实例名称(可选)
|
||||
TENANT_ID= # 租户ID(可选)
|
||||
```
|
||||
|
||||
## 核心目录结构
|
||||
|
||||
每个服务打包后应包含:
|
||||
|
||||
```
|
||||
服务名/
|
||||
├── bin/ # 可执行脚本(来自scripts目录)
|
||||
│ ├── start.sh
|
||||
│ ├── stop.sh
|
||||
│ ├── restart.sh
|
||||
│ └── status.sh
|
||||
├── lib/ # JAR文件和依赖
|
||||
│ ├── 服务名-version.jar
|
||||
│ └── 依赖.jar
|
||||
└── conf/ # 配置文件
|
||||
├── env.properties # 统一配置(来自scripts/env.properties)
|
||||
├── service.properties # 个性化配置(来自服务src/main/resources)
|
||||
├── application.yml
|
||||
└── logback-spring.xml
|
||||
```
|
||||
|
||||
## Assembly配置详解
|
||||
|
||||
### pom.xml配置
|
||||
```xml
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
```
|
||||
|
||||
### assembly.xml配置
|
||||
```xml
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0">
|
||||
<id>dist</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>true</includeBaseDirectory>
|
||||
|
||||
<fileSets>
|
||||
<!-- bin目录:使用项目根目录的统一脚本 -->
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/../../scripts</directory>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
<includes>
|
||||
<include>start.sh</include>
|
||||
<include>stop.sh</include>
|
||||
<include>restart.sh</include>
|
||||
<include>status.sh</include>
|
||||
</includes>
|
||||
<fileMode>0755</fileMode>
|
||||
</fileSet>
|
||||
|
||||
<!-- conf目录:统一配置 + 个性化配置 -->
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/../../scripts</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
<includes>
|
||||
<include>env.properties</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<directory>src/main/resources</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
<includes>
|
||||
<include>service.properties</include>
|
||||
<include>application.yml</include>
|
||||
<include>application-*.yml</include>
|
||||
<include>logback-spring.xml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
<!-- lib目录:服务JAR + 依赖 -->
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<useProjectArtifact>true</useProjectArtifact>
|
||||
<scope>runtime</scope>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
</assembly>
|
||||
```
|
||||
|
||||
## 自动构建脚本
|
||||
|
||||
### services-build.sh (项目根目录)
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 自动构建所有微服务,统一输出到deploy目录
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="${SCRIPT_DIR}"
|
||||
DEPLOY_DIR="${PROJECT_ROOT}/deploy"
|
||||
SERVICES=(
|
||||
"fund-gateway"
|
||||
"fund-sys"
|
||||
"fund-cust"
|
||||
"fund-proj"
|
||||
"fund-exp"
|
||||
"fund-receipt"
|
||||
"fund-report"
|
||||
"fund-req"
|
||||
"fund-file"
|
||||
)
|
||||
|
||||
# 确保部署目录存在
|
||||
mkdir -p "${DEPLOY_DIR}"
|
||||
|
||||
# 清理旧的部署包(可选)
|
||||
echo "清理旧部署包..."
|
||||
rm -f "${DEPLOY_DIR}"/*.tar.gz
|
||||
|
||||
build_service() {
|
||||
local service=$1
|
||||
local service_dir="${PROJECT_ROOT}/${service}"
|
||||
|
||||
echo "=== 构建服务: ${service} ==="
|
||||
|
||||
if [ ! -d "${service_dir}" ]; then
|
||||
echo "警告: 服务目录不存在 ${service_dir}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cd "${service_dir}"
|
||||
|
||||
# Maven构建
|
||||
mvn clean package -DskipTests
|
||||
|
||||
# 检查生成的tar.gz文件并复制到统一部署目录
|
||||
local tar_file=$(find target -name "${service}*.tar.gz" | head -1)
|
||||
if [ -n "${tar_file}" ]; then
|
||||
cp "${tar_file}" "${DEPLOY_DIR}/"
|
||||
echo "✓ ${service} 构建完成: $(basename ${tar_file})"
|
||||
else
|
||||
echo "✗ ${service} 构建失败:未找到tar.gz文件"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 主构建流程
|
||||
echo "开始批量构建微服务..."
|
||||
echo "项目根目录: ${PROJECT_ROOT}"
|
||||
echo "部署输出目录: ${DEPLOY_DIR}"
|
||||
echo ""
|
||||
|
||||
for service in "${SERVICES[@]}"; do
|
||||
build_service "${service}" || {
|
||||
echo "构建失败,退出"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== 构建完成 ==="
|
||||
echo "生成的部署包:"
|
||||
ls -lh "${DEPLOY_DIR}"/*.tar.gz
|
||||
echo ""
|
||||
echo "部署目录大小: $(du -sh "${DEPLOY_DIR}" | cut -f1)"
|
||||
```
|
||||
|
||||
## 启动脚本增强版
|
||||
|
||||
### start.sh (支持配置文件加载)
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 增强版启动脚本,自动加载env.properties和service.properties
|
||||
|
||||
APP_HOME=$(cd "$(dirname "$0")/.." && pwd)
|
||||
PID_FILE="/tmp/${INSTANCE_NAME}.pid"
|
||||
|
||||
# 配置文件加载函数
|
||||
load_properties() {
|
||||
local file=$1
|
||||
if [[ -f "$file" ]]; then
|
||||
while IFS='=' read -r key value; do
|
||||
[[ -z "$key" || "$key" =~ ^# ]] && continue
|
||||
export "$key=$value"
|
||||
done < "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
# 1. 加载统一配置
|
||||
load_properties "${APP_HOME}/conf/env.properties"
|
||||
|
||||
# 2. 加载服务个性化配置(覆盖统一配置)
|
||||
load_properties "${APP_HOME}/conf/service.properties"
|
||||
|
||||
# 3. 设置默认值
|
||||
APP_NAME=${APP_NAME:-"unknown"}
|
||||
INSTANCE_NAME=${INSTANCE_NAME:-${APP_NAME}}
|
||||
TENANT_ID=${TENANT_ID:-""}
|
||||
|
||||
# 4. 查找主JAR文件
|
||||
JAR_FILE=$(find "${APP_HOME}/lib" -name "${APP_NAME}*.jar" | head -1)
|
||||
if [[ -z "$JAR_FILE" ]]; then
|
||||
echo "错误: 未找到JAR文件 ${APP_NAME}*.jar"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 5. 构建JVM参数
|
||||
JAVA_OPTS="-Xms256m -Xmx512m"
|
||||
JAVA_OPTS="$JAVA_OPTS -Dspring.config.location=${APP_HOME}/conf/"
|
||||
JAVA_OPTS="$JAVA_OPTS -Dlogging.config=${APP_HOME}/conf/logback-spring.xml"
|
||||
|
||||
# 6. 启动应用
|
||||
echo "启动服务: ${INSTANCE_NAME}"
|
||||
echo "JAR文件: $(basename $JAR_FILE)"
|
||||
echo "租户ID: ${TENANT_ID:-'共享实例'}"
|
||||
|
||||
nohup java $JAVA_OPTS -jar "$JAR_FILE" > /dev/null 2>&1 &
|
||||
echo $! > "${PID_FILE}"
|
||||
echo "${INSTANCE_NAME} 启动成功,PID: $(cat ${PID_FILE})"
|
||||
```
|
||||
|
||||
## 配置文件验证
|
||||
|
||||
### 配置检查脚本
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# validate-config.sh - 验证配置文件完整性
|
||||
|
||||
APP_HOME=$(cd "$(dirname "$0")/.." && pwd)
|
||||
|
||||
echo "=== 配置文件验证 ==="
|
||||
|
||||
# 检查必需文件
|
||||
REQUIRED_FILES=(
|
||||
"conf/env.properties"
|
||||
"conf/service.properties"
|
||||
"conf/application.yml"
|
||||
"lib/${APP_NAME}*.jar"
|
||||
)
|
||||
|
||||
for file_pattern in "${REQUIRED_FILES[@]}"; do
|
||||
if ls "${APP_HOME}/${file_pattern}" >/dev/null 2>&1; then
|
||||
echo "✓ ${file_pattern}"
|
||||
else
|
||||
echo "✗ ${file_pattern} (缺失)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# 验证service.properties必需参数
|
||||
SERVICE_CONF="${APP_HOME}/conf/service.properties"
|
||||
REQUIRED_PARAMS=("APP_NAME" "MAIN_CLASS")
|
||||
|
||||
for param in "${REQUIRED_PARAMS[@]}"; do
|
||||
if grep -q "^${param}=" "${SERVICE_CONF}"; then
|
||||
value=$(grep "^${param}=" "${SERVICE_CONF}" | cut -d'=' -f2)
|
||||
echo "✓ ${param}=${value}"
|
||||
else
|
||||
echo "✗ 缺少必需参数: ${param}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "配置验证通过!"
|
||||
```
|
||||
|
||||
## 打包命令
|
||||
|
||||
```bash
|
||||
# 构建单个服务
|
||||
cd fund-sys && mvn clean package
|
||||
|
||||
# 批量构建所有服务
|
||||
cd /项目根目录 && ./scripts/services-build.sh
|
||||
|
||||
# 跳过测试快速构建
|
||||
mvn clean package -DskipTests
|
||||
|
||||
# 验证打包结果
|
||||
tar -tzf target/fund-sys.tar.gz | head -10
|
||||
```
|
||||
|
||||
## 部署验证清单
|
||||
|
||||
构建完成后验证:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# deployment-check.sh
|
||||
|
||||
TAR_FILE=$1
|
||||
|
||||
echo "=== 部署包验证 ==="
|
||||
echo "包文件: ${TAR_FILE}"
|
||||
|
||||
# 结构验证
|
||||
echo "目录结构:"
|
||||
tar -tzf "${TAR_FILE}" | grep -E "^(bin/|lib/|conf/)" | sort
|
||||
|
||||
# 关键文件验证
|
||||
echo "必需文件检查:"
|
||||
REQUIRED=(
|
||||
"bin/start.sh"
|
||||
"bin/stop.sh"
|
||||
"conf/env.properties"
|
||||
"conf/service.properties"
|
||||
)
|
||||
|
||||
for file in "${REQUIRED[@]}"; do
|
||||
if tar -tzf "${TAR_FILE}" | grep -q "^${file}$"; then
|
||||
echo "✓ ${file}"
|
||||
else
|
||||
echo "✗ ${file}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# 权限验证
|
||||
echo "脚本权限检查:"
|
||||
SCRIPTS=$(tar -tzf "${TAR_FILE}" | grep "^bin/.*\.sh$")
|
||||
for script in ${SCRIPTS}; do
|
||||
echo "✓ ${script} (可执行)"
|
||||
done
|
||||
|
||||
echo "验证完成!"
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **配置分离**: 统一配置放`scripts/env.properties`,个性化配置放各服务`service.properties`
|
||||
2. **构建脚本**: 使用统一的`services-build.sh`批量构建
|
||||
3. **版本管理**: 在`service.properties`中明确指定`APP_NAME`和`MAIN_CLASS`
|
||||
4. **多租户支持**: 通过`TENANT_ID`参数支持共享实例和VIP专属实例
|
||||
5. **权限控制**: 确保bin目录脚本具有可执行权限(755)
|
||||
6. **验证机制**: 构建后使用验证脚本检查包完整性
|
||||
7. **部署目录管理**: 所有部署包统一存储在项目根目录`deploy/`下,实现开发与部署物理分离
|
||||
8. **CI/CD集成**: 部署目录结构便于自动化部署和版本发布管理
|
||||
610
.qoder/skills/maven-assembly/examples.md
Normal file
610
.qoder/skills/maven-assembly/examples.md
Normal file
@ -0,0 +1,610 @@
|
||||
# 资金服务平台 Assembly 使用示例
|
||||
|
||||
## 基础配置示例
|
||||
|
||||
### 1. 服务模块标准配置
|
||||
|
||||
**目录结构(包含部署目录管理):**
|
||||
```
|
||||
fundplatform/
|
||||
├── deploy/ # 部署产物目录(核心实践)
|
||||
│ ├── fund-gateway.tar.gz # 网关服务部署包
|
||||
│ ├── fund-sys.tar.gz # 系统服务部署包
|
||||
│ └── ... 其他服务部署包
|
||||
├── scripts/ # 统一脚本和配置
|
||||
│ ├── env.properties # 统一配置文件
|
||||
│ ├── services-build.sh # 批量构建脚本
|
||||
│ └── start.sh # 通用启动脚本
|
||||
├── fund-sys/ # 服务源代码
|
||||
│ ├── src/
|
||||
│ │ ├── main/
|
||||
│ │ │ ├── assembly/
|
||||
│ │ │ │ └── assembly.xml
|
||||
│ │ │ └── resources/
|
||||
│ │ │ ├── service.properties
|
||||
│ │ │ ├── application.yml
|
||||
│ │ │ └── logback-spring.xml
|
||||
│ │ └── test/
|
||||
│ ├── pom.xml
|
||||
│ └── target/
|
||||
│ └── fund-sys.tar.gz # 临时构建产物
|
||||
└── ... 其他服务模块
|
||||
```
|
||||
|
||||
**核心实践要点**:
|
||||
- 所有部署包统一存储在项目根目录的 `deploy/` 目录下
|
||||
- 开发代码与部署产物物理分离,便于版本管理和CI/CD集成
|
||||
- 通过 `scripts/services-build.sh` 脚本自动收集各服务构建产物
|
||||
|
||||
**pom.xml配置:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.fundplatform</groupId>
|
||||
<artifactId>fund-platform</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>fund-sys</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<!-- 从service.properties读取主类 -->
|
||||
<main.class>com.fundplatform.sys.SysApplication</main.class>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>${main.class}</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
```
|
||||
|
||||
**service.properties配置:**
|
||||
```properties
|
||||
# ============================================
|
||||
# fund-sys 服务配置
|
||||
# ============================================
|
||||
|
||||
APP_NAME=fund-sys
|
||||
MAIN_CLASS=com.fundplatform.sys.SysApplication
|
||||
INSTANCE_NAME=fund-sys
|
||||
TENANT_ID=
|
||||
|
||||
# 可选配置
|
||||
SERVER_PORT=8100
|
||||
```
|
||||
|
||||
### 2. Assembly Descriptor配置
|
||||
|
||||
**src/main/assembly/assembly.xml:**
|
||||
```xml
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0">
|
||||
<id>dist</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>true</includeBaseDirectory>
|
||||
|
||||
<fileSets>
|
||||
<!-- 使用项目根目录的统一脚本 -->
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/../../scripts</directory>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
<includes>
|
||||
<include>start.sh</include>
|
||||
<include>stop.sh</include>
|
||||
<include>restart.sh</include>
|
||||
<include>status.sh</include>
|
||||
</includes>
|
||||
<fileMode>0755</fileMode>
|
||||
</fileSet>
|
||||
|
||||
<!-- 统一配置文件 -->
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/../../scripts</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
<includes>
|
||||
<include>env.properties</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
<!-- 服务个性化配置 -->
|
||||
<fileSet>
|
||||
<directory>src/main/resources</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
<includes>
|
||||
<include>service.properties</include>
|
||||
<include>application.yml</include>
|
||||
<include>logback-spring.xml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<useProjectArtifact>true</useProjectArtifact>
|
||||
<scope>runtime</scope>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
</assembly>
|
||||
```
|
||||
|
||||
## 实际应用场景
|
||||
|
||||
### 场景1: 单服务构建与部署
|
||||
|
||||
**构建命令:**
|
||||
```bash
|
||||
# 进入服务目录
|
||||
cd fund-sys
|
||||
|
||||
# 清理并构建
|
||||
mvn clean package -DskipTests
|
||||
|
||||
# 验证构建结果
|
||||
ls -lh target/fund-sys.tar.gz
|
||||
|
||||
# 查看包内容
|
||||
tar -tzf target/fund-sys.tar.gz | head -10
|
||||
```
|
||||
|
||||
**部署验证:**
|
||||
```bash
|
||||
# 解压部署包
|
||||
mkdir -p /opt/deploy/fund-sys
|
||||
tar -xzf target/fund-sys.tar.gz -C /opt/deploy/
|
||||
|
||||
# 验证配置文件
|
||||
cat /opt/deploy/fund-sys/conf/service.properties
|
||||
cat /opt/deploy/fund-sys/conf/env.properties
|
||||
|
||||
# 启动服务
|
||||
cd /opt/deploy/fund-sys
|
||||
./bin/start.sh
|
||||
```
|
||||
|
||||
### 场景2: 批量构建所有服务(部署目录管理实践)
|
||||
|
||||
**创建批量构建脚本 (scripts/services-build.sh):**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 资金服务平台批量构建脚本 - 统一输出到deploy目录
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="${SCRIPT_DIR}"
|
||||
DEPLOY_DIR="${PROJECT_ROOT}/deploy"
|
||||
|
||||
# 服务列表
|
||||
SERVICES=(
|
||||
"fund-gateway"
|
||||
"fund-sys"
|
||||
"fund-cust"
|
||||
"fund-proj"
|
||||
"fund-exp"
|
||||
"fund-receipt"
|
||||
"fund-report"
|
||||
"fund-req"
|
||||
"fund-file"
|
||||
)
|
||||
|
||||
# 部署目录初始化
|
||||
initialize_deploy_directory() {
|
||||
echo "=== 部署目录初始化 ==="
|
||||
|
||||
# 创建部署目录
|
||||
mkdir -p "${DEPLOY_DIR}"
|
||||
echo "✓ 部署目录: ${DEPLOY_DIR}"
|
||||
|
||||
# 显示当前部署包
|
||||
echo "当前部署包:"
|
||||
if ls "${DEPLOY_DIR}"/*.tar.gz >/dev/null 2>&1; then
|
||||
ls -lh "${DEPLOY_DIR}"/*.tar.gz
|
||||
else
|
||||
echo " (无)"
|
||||
fi
|
||||
|
||||
# 询问是否清理旧包
|
||||
echo ""
|
||||
read -p "是否清理旧的部署包? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
rm -f "${DEPLOY_DIR}"/*.tar.gz
|
||||
echo "✓ 已清理旧部署包"
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
build_service() {
|
||||
local service=$1
|
||||
local service_dir="${PROJECT_ROOT}/${service}"
|
||||
|
||||
echo "=== 构建服务: ${service} ==="
|
||||
|
||||
if [ ! -d "${service_dir}" ]; then
|
||||
echo "服务目录不存在: ${service_dir}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cd "${service_dir}"
|
||||
|
||||
# Maven构建
|
||||
mvn clean package -DskipTests -q
|
||||
|
||||
# 复制到统一部署目录
|
||||
local tar_file=$(find target -name "${service}*.tar.gz" | head -1)
|
||||
if [ -n "${tar_file}" ]; then
|
||||
cp "${tar_file}" "${DEPLOY_DIR}/"
|
||||
local file_size=$(du -h "${tar_file}" | cut -f1)
|
||||
echo "✓ ${service} 构建完成 (${file_size})"
|
||||
echo " 输出到: ${DEPLOY_DIR}/$(basename ${tar_file})"
|
||||
else
|
||||
echo "✗ ${service} 构建失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 主构建流程
|
||||
main() {
|
||||
echo "========================================="
|
||||
echo " 资金服务平台批量构建"
|
||||
echo " 部署目录: ${DEPLOY_DIR}"
|
||||
echo "========================================="
|
||||
|
||||
# 初始化部署目录
|
||||
initialize_deploy_directory
|
||||
|
||||
local success_count=0
|
||||
local fail_count=0
|
||||
|
||||
# 批量构建
|
||||
for service in "${SERVICES[@]}"; do
|
||||
if build_service "${service}"; then
|
||||
((success_count++))
|
||||
else
|
||||
((fail_count++))
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "========================================="
|
||||
echo "构建完成统计:"
|
||||
echo " 成功: ${success_count}"
|
||||
echo " 失败: ${fail_count}"
|
||||
echo ""
|
||||
|
||||
if [ ${fail_count} -eq 0 ]; then
|
||||
echo "✓ 所有服务构建成功!"
|
||||
echo ""
|
||||
echo "生成的部署包:"
|
||||
ls -lh "${DEPLOY_DIR}"/*.tar.gz
|
||||
echo ""
|
||||
echo "部署目录总大小: $(du -sh "${DEPLOY_DIR}" | cut -f1)"
|
||||
else
|
||||
echo "✗ ${fail_count}个服务构建失败"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
```
|
||||
|
||||
**使用方法:**
|
||||
```bash
|
||||
# 给脚本执行权限
|
||||
chmod +x scripts/services-build.sh
|
||||
|
||||
# 执行批量构建
|
||||
./scripts/services-build.sh
|
||||
|
||||
# 构建完成后查看部署目录
|
||||
ls -lh deploy/
|
||||
|
||||
# 验证部署包完整性
|
||||
scripts/validate-deployment.sh
|
||||
```
|
||||
|
||||
**部署目录管理优势**:
|
||||
1. **统一管理**:所有服务部署包集中存储在 `deploy/` 目录
|
||||
2. **版本控制**:便于CI/CD流水线统一处理部署包
|
||||
3. **权限分离**:开发代码与部署产物物理分离
|
||||
4. **清理维护**:易于批量清理旧版本部署包
|
||||
|
||||
**使用方法:**
|
||||
```bash
|
||||
# 给脚本执行权限
|
||||
chmod +x scripts/services-build.sh
|
||||
|
||||
# 执行批量构建
|
||||
./scripts/services-build.sh
|
||||
```
|
||||
|
||||
### 场景3: 多租户实例部署
|
||||
|
||||
**共享实例配置:**
|
||||
```properties
|
||||
# fund-sys/src/main/resources/service.properties
|
||||
APP_NAME=fund-sys
|
||||
MAIN_CLASS=com.fundplatform.sys.SysApplication
|
||||
INSTANCE_NAME=fund-sys-shared
|
||||
TENANT_ID=
|
||||
```
|
||||
|
||||
**VIP专属实例配置:**
|
||||
```properties
|
||||
# fund-sys-vip001/src/main/resources/service.properties
|
||||
APP_NAME=fund-sys
|
||||
MAIN_CLASS=com.fundplatform.sys.SysApplication
|
||||
INSTANCE_NAME=fund-sys-vip001
|
||||
TENANT_ID=vip001
|
||||
```
|
||||
|
||||
**部署脚本支持多实例:**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# multi-instance-deploy.sh
|
||||
|
||||
INSTANCE_TYPE=${1:-"shared"} # shared 或 vip001
|
||||
SERVICE_NAME="fund-sys"
|
||||
|
||||
case "${INSTANCE_TYPE}" in
|
||||
shared)
|
||||
CONFIG_SUFFIX=""
|
||||
DEPLOY_PATH="/opt/apps/${SERVICE_NAME}-shared"
|
||||
;;
|
||||
vip*)
|
||||
CONFIG_SUFFIX="-${INSTANCE_TYPE}"
|
||||
DEPLOY_PATH="/opt/apps/${SERVICE_NAME}-${INSTANCE_TYPE}"
|
||||
;;
|
||||
*)
|
||||
echo "未知实例类型: ${INSTANCE_TYPE}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# 构建特定实例
|
||||
cd "${SERVICE_NAME}${CONFIG_SUFFIX}"
|
||||
mvn clean package -DskipTests
|
||||
|
||||
# 部署
|
||||
mkdir -p "${DEPLOY_PATH}"
|
||||
tar -xzf target/${SERVICE_NAME}*.tar.gz -C "${DEPLOY_PATH}"
|
||||
|
||||
# 启动
|
||||
${DEPLOY_PATH}/bin/start.sh
|
||||
```
|
||||
|
||||
## 高级配置示例
|
||||
|
||||
### 场景4: 环境差异化配置
|
||||
|
||||
**开发环境配置 (dev-env.properties):**
|
||||
```properties
|
||||
# scripts/dev-env.properties
|
||||
NACOS_SERVER_ADDR=dev-nacos:8848
|
||||
REDIS_HOST=dev-redis
|
||||
REDIS_PASSWORD=dev-password
|
||||
LOG_LEVEL_ROOT=DEBUG
|
||||
```
|
||||
|
||||
**生产环境配置 (prod-env.properties):**
|
||||
```properties
|
||||
# scripts/prod-env.properties
|
||||
NACOS_SERVER_ADDR=prod-nacos:8848
|
||||
REDIS_HOST=prod-redis
|
||||
REDIS_PASSWORD=prod-password
|
||||
LOG_LEVEL_ROOT=INFO
|
||||
```
|
||||
|
||||
**Profile配置:**
|
||||
```xml
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>dev</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/dev-assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/prod-assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
```
|
||||
|
||||
### 场景5: 条件配置打包
|
||||
|
||||
**assembly.xml支持条件包含:**
|
||||
```xml
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0">
|
||||
<id>conditional-dist</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
|
||||
<fileSets>
|
||||
<!-- 基础文件 -->
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/../../scripts</directory>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
<includes>
|
||||
<include>start.sh</include>
|
||||
<include>stop.sh</include>
|
||||
</includes>
|
||||
<fileMode>0755</fileMode>
|
||||
</fileSet>
|
||||
|
||||
<!-- 根据环境包含不同配置 -->
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/../../scripts/${env.name}</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
<includes>
|
||||
<include>env.properties</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
<!-- 可选安全组件 -->
|
||||
<fileSet>
|
||||
<directory>src/main/security</directory>
|
||||
<outputDirectory>security</outputDirectory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
```
|
||||
|
||||
## 构建验证示例
|
||||
|
||||
### 自动化验证脚本
|
||||
|
||||
**创建验证脚本 (scripts/validate-build.sh):**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 构建结果验证脚本
|
||||
|
||||
validate_service() {
|
||||
local service=$1
|
||||
local tar_file="target/${service}.tar.gz"
|
||||
|
||||
echo "验证 ${service}..."
|
||||
|
||||
# 检查文件存在
|
||||
if [ ! -f "${tar_file}" ]; then
|
||||
echo "✗ 未找到部署包: ${tar_file}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 检查包结构
|
||||
local required_files=(
|
||||
"bin/start.sh"
|
||||
"bin/stop.sh"
|
||||
"conf/env.properties"
|
||||
"conf/service.properties"
|
||||
"lib/${service}*.jar"
|
||||
)
|
||||
|
||||
for file in "${required_files[@]}"; do
|
||||
if ! tar -tzf "${tar_file}" | grep -q "${file}"; then
|
||||
echo "✗ 缺失文件: ${file}"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "✓ ${service} 验证通过"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 验证所有服务
|
||||
SERVICES=("fund-gateway" "fund-sys" "fund-cust" "fund-proj"
|
||||
"fund-exp" "fund-receipt" "fund-report" "fund-req" "fund-file")
|
||||
|
||||
for service in "${SERVICES[@]}"; do
|
||||
if [ -d "${service}" ]; then
|
||||
cd "${service}"
|
||||
validate_service "${service}" || exit 1
|
||||
cd ..
|
||||
fi
|
||||
done
|
||||
|
||||
echo "所有服务验证完成!"
|
||||
```
|
||||
|
||||
### 部署前检查清单
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# pre-deployment-check.sh
|
||||
|
||||
echo "=== 部署前检查清单 ==="
|
||||
|
||||
# 1. 检查配置文件完整性
|
||||
echo "1. 配置文件检查:"
|
||||
for service in fund-*; do
|
||||
if [ -d "${service}" ]; then
|
||||
conf_file="${service}/src/main/resources/service.properties"
|
||||
if [ -f "${conf_file}" ]; then
|
||||
echo "✓ ${service}: service.properties 存在"
|
||||
# 检查必需参数
|
||||
if grep -q "APP_NAME=" "${conf_file}" && grep -q "MAIN_CLASS=" "${conf_file}"; then
|
||||
echo "✓ ${service}: 必需参数完整"
|
||||
else
|
||||
echo "✗ ${service}: 缺少必需参数"
|
||||
fi
|
||||
else
|
||||
echo "✗ ${service}: 缺少 service.properties"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 2. 检查统一配置
|
||||
echo "2. 统一配置检查:"
|
||||
if [ -f "scripts/env.properties" ]; then
|
||||
echo "✓ scripts/env.properties 存在"
|
||||
else
|
||||
echo "✗ 缺少统一配置文件"
|
||||
fi
|
||||
|
||||
# 3. 检查构建脚本
|
||||
echo "3. 构建脚本检查:"
|
||||
if [ -f "scripts/services-build.sh" ]; then
|
||||
echo "✓ 批量构建脚本存在"
|
||||
else
|
||||
echo "✗ 缺少批量构建脚本"
|
||||
fi
|
||||
|
||||
echo "检查完成!"
|
||||
```
|
||||
|
||||
这些示例展示了资金服务平台Assembly配置的各种实际应用场景,涵盖了从基础配置到高级特性的完整使用方式。
|
||||
658
.qoder/skills/maven-assembly/reference.md
Normal file
658
.qoder/skills/maven-assembly/reference.md
Normal file
@ -0,0 +1,658 @@
|
||||
# 资金服务平台 Assembly 配置参考
|
||||
|
||||
## 项目专用配置详解
|
||||
|
||||
### 部署目录管理实践
|
||||
|
||||
**核心原则**:所有部署打包文件统一存储在项目根目录的 `deploy/` 目录下,实现开发代码与部署产物的物理分离。
|
||||
|
||||
```
|
||||
fundplatform/
|
||||
├── deploy/ # 部署产物目录(核心实践)
|
||||
│ ├── fund-gateway.tar.gz # 网关服务部署包
|
||||
│ ├── fund-sys.tar.gz # 系统服务部署包
|
||||
│ ├── fund-cust.tar.gz # 客户服务部署包
|
||||
│ └── ... 其他服务部署包
|
||||
├── scripts/ # 统一脚本和配置
|
||||
└── 各服务源代码目录 # 开发代码(与部署分离)
|
||||
```
|
||||
|
||||
**实践优势**:
|
||||
- **物理分离**:开发代码与部署产物完全隔离
|
||||
- **版本管理**:便于CI/CD流水线统一管理部署包
|
||||
- **权限控制**:可以对部署目录设置不同的访问权限
|
||||
- **清理维护**:易于批量清理旧版本部署包
|
||||
|
||||
### 统一配置文件管理
|
||||
|
||||
#### scripts/env.properties 配置
|
||||
这是所有服务共享的统一配置文件,包含基础设施配置:
|
||||
|
||||
```properties
|
||||
# ============================================
|
||||
# 环境变量配置文件(所有服务共用)
|
||||
# ============================================
|
||||
|
||||
# Nacos配置
|
||||
NACOS_SERVER_ADDR=localhost:8848
|
||||
NACOS_NAMESPACE=fund-platform
|
||||
NACOS_GROUP=DEFAULT_GROUP
|
||||
NACOS_USERNAME=nacos
|
||||
NACOS_PASSWORD=nacos
|
||||
|
||||
# Redis配置
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=zjf@123456
|
||||
REDIS_DATABASE=0
|
||||
|
||||
# 数据库连接池
|
||||
HIKARI_MINIMUM_IDLE=5
|
||||
HIKARI_CONNECTION_TIMEOUT=30000
|
||||
|
||||
# 日志配置
|
||||
LOG_HOME=/datacfs/applogs
|
||||
LOG_LEVEL_ROOT=INFO
|
||||
LOG_LEVEL_APP=DEBUG
|
||||
|
||||
# 多租户配置
|
||||
TENANT_ROUTING_ENABLED=true
|
||||
DEFAULT_TENANT_ID=1
|
||||
|
||||
# 腾讯云COS
|
||||
COS_ENABLED=true
|
||||
COS_SECRET_ID=your-secret-id
|
||||
COS_SECRET_KEY=your-secret-key
|
||||
```
|
||||
|
||||
#### 服务个性化配置 (service.properties)
|
||||
每个服务必须包含的最小配置:
|
||||
|
||||
```properties
|
||||
# ============================================
|
||||
# 服务个性化配置
|
||||
# ============================================
|
||||
|
||||
# 必需参数
|
||||
APP_NAME=fund-sys # 服务名称(必须)
|
||||
MAIN_CLASS=com.fundplatform.sys.SysApplication # 主启动类(必须)
|
||||
|
||||
# 可选参数
|
||||
INSTANCE_NAME= # 实例名称(默认等于APP_NAME)
|
||||
TENANT_ID= # 租户ID(空=共享实例)
|
||||
SERVER_PORT=8100 # 服务端口(可选)
|
||||
```
|
||||
|
||||
### 完整的pom.xml插件配置
|
||||
|
||||
```xml
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Spring Boot插件 -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>${main.class}</mainClass>
|
||||
<layout>ZIP</layout>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Assembly插件 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<!-- 从service.properties读取主类 -->
|
||||
<main.class>${service.main.class}</main.class>
|
||||
</properties>
|
||||
```
|
||||
|
||||
### 项目级Assembly Descriptor
|
||||
|
||||
```xml
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0
|
||||
http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||
<id>dist</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>true</includeBaseDirectory>
|
||||
|
||||
<fileSets>
|
||||
<!-- bin目录:使用项目根目录统一脚本 -->
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/../../scripts</directory>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
<includes>
|
||||
<include>start.sh</include>
|
||||
<include>stop.sh</include>
|
||||
<include>restart.sh</include>
|
||||
<include>status.sh</include>
|
||||
</includes>
|
||||
<fileMode>0755</fileMode>
|
||||
<directoryMode>0755</directoryMode>
|
||||
</fileSet>
|
||||
|
||||
<!-- 统一配置文件 -->
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/../../scripts</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
<includes>
|
||||
<include>env.properties</include>
|
||||
</includes>
|
||||
<fileMode>0644</fileMode>
|
||||
</fileSet>
|
||||
|
||||
<!-- 服务个性化配置 -->
|
||||
<fileSet>
|
||||
<directory>src/main/resources</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
<includes>
|
||||
<include>service.properties</include>
|
||||
<include>application.yml</include>
|
||||
<include>application-*.yml</include>
|
||||
<include>logback-spring.xml</include>
|
||||
</includes>
|
||||
<fileMode>0644</fileMode>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<useProjectArtifact>true</useProjectArtifact>
|
||||
<useTransitiveDependencies>true</useTransitiveDependencies>
|
||||
<scope>runtime</scope>
|
||||
<fileMode>0644</fileMode>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
</assembly>
|
||||
```
|
||||
|
||||
## 配置文件加载机制
|
||||
|
||||
### 启动脚本中的配置加载顺序
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 配置加载的核心逻辑
|
||||
|
||||
APP_HOME=$(cd "$(dirname "$0")/.." && pwd)
|
||||
|
||||
# 1. 加载统一配置(基础环境)
|
||||
load_properties() {
|
||||
local file=$1
|
||||
if [[ -f "$file" ]]; then
|
||||
while IFS='=' read -r key value; do
|
||||
# 跳过空行和注释
|
||||
[[ -z "$key" || "$key" =~ ^[[:space:]]*# ]] && continue
|
||||
# 导出环境变量
|
||||
export "$key=$value"
|
||||
done < "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
# 加载顺序:先统一配置,后个性化配置(后者覆盖前者)
|
||||
load_properties "${APP_HOME}/conf/env.properties"
|
||||
load_properties "${APP_HOME}/conf/service.properties"
|
||||
|
||||
# 设置默认值
|
||||
APP_NAME=${APP_NAME:-"unknown-service"}
|
||||
INSTANCE_NAME=${INSTANCE_NAME:-${APP_NAME}}
|
||||
TENANT_ID=${TENANT_ID:-""}
|
||||
```
|
||||
|
||||
### 配置验证脚本
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# validate-service-config.sh
|
||||
|
||||
APP_HOME=$(cd "$(dirname "$0")/.." && pwd)
|
||||
CONFIG_DIR="${APP_HOME}/conf"
|
||||
|
||||
echo "=== 服务配置验证 ==="
|
||||
|
||||
# 1. 检查配置文件存在性
|
||||
CONFIG_FILES=("env.properties" "service.properties" "application.yml")
|
||||
for file in "${CONFIG_FILES[@]}"; do
|
||||
if [[ -f "${CONFIG_DIR}/${file}" ]]; then
|
||||
echo "✓ ${file}"
|
||||
else
|
||||
echo "✗ ${file} (缺失)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# 2. 验证service.properties必需参数
|
||||
SERVICE_CONF="${CONFIG_DIR}/service.properties"
|
||||
REQUIRED_PARAMS=("APP_NAME" "MAIN_CLASS")
|
||||
|
||||
echo "验证必需参数:"
|
||||
for param in "${REQUIRED_PARAMS[@]}"; do
|
||||
if grep -q "^${param}=" "${SERVICE_CONF}"; then
|
||||
value=$(grep "^${param}=" "${SERVICE_CONF}" | cut -d'=' -f2 | xargs)
|
||||
echo "✓ ${param}=${value}"
|
||||
else
|
||||
echo "✗ 缺少必需参数: ${param}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# 3. 验证JAR文件
|
||||
JAR_PATTERN="${APP_NAME}*.jar"
|
||||
JAR_FILE=$(find "${APP_HOME}/lib" -name "${JAR_PATTERN}" 2>/dev/null | head -1)
|
||||
|
||||
if [[ -n "$JAR_FILE" ]]; then
|
||||
echo "✓ 服务JAR: $(basename $JAR_FILE)"
|
||||
else
|
||||
echo "✗ 未找到服务JAR文件: ${JAR_PATTERN}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "配置验证通过!"
|
||||
```
|
||||
|
||||
## 多租户配置支持
|
||||
|
||||
### 共享实例配置
|
||||
```properties
|
||||
# service.properties
|
||||
APP_NAME=fund-sys
|
||||
INSTANCE_NAME=fund-sys
|
||||
TENANT_ID=
|
||||
```
|
||||
|
||||
### VIP专属实例配置
|
||||
```properties
|
||||
# service.properties
|
||||
APP_NAME=fund-sys
|
||||
INSTANCE_NAME=fund-sys-vip001
|
||||
TENANT_ID=vip001
|
||||
```
|
||||
|
||||
### 启动脚本多租户支持
|
||||
```bash
|
||||
# 根据TENANT_ID设置不同的Nacos元数据
|
||||
if [[ -n "${TENANT_ID}" ]]; then
|
||||
JAVA_OPTS="$JAVA_OPTS -Dspring.cloud.nacos.discovery.metadata.tenant=${TENANT_ID}"
|
||||
echo "启动VIP实例: ${INSTANCE_NAME} (租户: ${TENANT_ID})"
|
||||
else
|
||||
echo "启动共享实例: ${INSTANCE_NAME}"
|
||||
fi
|
||||
```
|
||||
|
||||
## 构建自动化脚本
|
||||
|
||||
### 批量构建脚本 (scripts/services-build.sh)
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 资金服务平台批量构建脚本 - 统一输出到deploy目录
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="${SCRIPT_DIR}"
|
||||
DEPLOY_DIR="${PROJECT_ROOT}/deploy"
|
||||
|
||||
# 服务列表(按依赖顺序)
|
||||
SERVICES=(
|
||||
"fund-gateway"
|
||||
"fund-sys"
|
||||
"fund-cust"
|
||||
"fund-proj"
|
||||
"fund-exp"
|
||||
"fund-receipt"
|
||||
"fund-report"
|
||||
"fund-req"
|
||||
"fund-file"
|
||||
)
|
||||
|
||||
# 部署目录管理
|
||||
setup_deploy_directory() {
|
||||
echo "=== 部署目录管理 ==="
|
||||
|
||||
# 创建部署目录
|
||||
mkdir -p "${DEPLOY_DIR}"
|
||||
echo "✓ 部署目录: ${DEPLOY_DIR}"
|
||||
|
||||
# 显示当前部署包
|
||||
echo "当前部署包:"
|
||||
if ls "${DEPLOY_DIR}"/*.tar.gz >/dev/null 2>&1; then
|
||||
ls -lh "${DEPLOY_DIR}"/*.tar.gz
|
||||
else
|
||||
echo " (无)"
|
||||
fi
|
||||
|
||||
# 询问是否清理旧包
|
||||
echo ""
|
||||
read -p "是否清理旧的部署包? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
rm -f "${DEPLOY_DIR}"/*.tar.gz
|
||||
echo "✓ 已清理旧部署包"
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 构建单个服务
|
||||
build_service() {
|
||||
local service=$1
|
||||
local service_dir="${PROJECT_ROOT}/${service}"
|
||||
local start_time=$(date +%s)
|
||||
|
||||
echo "=== 构建服务: ${service} ==="
|
||||
|
||||
# 检查服务目录
|
||||
if [ ! -d "${service_dir}" ]; then
|
||||
echo "警告: 服务目录不存在 ${service_dir}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cd "${service_dir}"
|
||||
|
||||
# 清理并构建
|
||||
echo "清理并构建..."
|
||||
mvn clean package -DskipTests -q
|
||||
|
||||
# 查找生成的tar.gz文件
|
||||
local tar_file=$(find target -name "${service}-*.tar.gz" | head -1)
|
||||
|
||||
if [ -n "${tar_file}" ]; then
|
||||
# 复制到统一部署目录
|
||||
cp "${tar_file}" "${DEPLOY_DIR}/"
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
local file_size=$(du -h "${tar_file}" | cut -f1)
|
||||
|
||||
echo "✓ ${service} 构建成功 (${duration}秒, ${file_size})"
|
||||
echo " 输出到统一部署目录: ${DEPLOY_DIR}/$(basename ${tar_file})"
|
||||
else
|
||||
echo "✗ ${service} 构建失败:未找到tar.gz文件"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 部署包验证
|
||||
validate_deployment_packages() {
|
||||
echo ""
|
||||
echo "=== 部署包验证 ==="
|
||||
|
||||
local package_count=0
|
||||
local total_size=0
|
||||
|
||||
for tar_file in "${DEPLOY_DIR}"/*.tar.gz; do
|
||||
if [[ -f "${tar_file}" ]]; then
|
||||
local file_size=$(du -m "${tar_file}" | cut -f1)
|
||||
total_size=$((total_size + file_size))
|
||||
((package_count++))
|
||||
|
||||
# 基本验证
|
||||
if tar -tzf "${tar_file}" >/dev/null 2>&1; then
|
||||
echo "✓ $(basename ${tar_file}) [${file_size}MB]"
|
||||
else
|
||||
echo "✗ $(basename ${tar_file}) [损坏]"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "总计: ${package_count}个部署包, ${total_size}MB"
|
||||
}
|
||||
|
||||
# 主构建流程
|
||||
main() {
|
||||
local total_start=$(date +%s)
|
||||
|
||||
echo "========================================="
|
||||
echo " 资金服务平台批量构建"
|
||||
echo " 部署目录: ${DEPLOY_DIR}"
|
||||
echo "========================================="
|
||||
echo "项目根目录: ${PROJECT_ROOT}"
|
||||
echo "服务数量: ${#SERVICES[@]}"
|
||||
echo ""
|
||||
|
||||
# 设置部署目录
|
||||
setup_deploy_directory
|
||||
|
||||
local success_count=0
|
||||
local fail_count=0
|
||||
|
||||
# 逐个构建服务
|
||||
for service in "${SERVICES[@]}"; do
|
||||
if build_service "${service}"; then
|
||||
((success_count++))
|
||||
else
|
||||
((fail_count++))
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
|
||||
local total_end=$(date +%s)
|
||||
local total_duration=$((total_end - total_start))
|
||||
|
||||
echo "========================================="
|
||||
echo "构建完成统计:"
|
||||
echo " 成功: ${success_count}"
|
||||
echo " 失败: ${fail_count}"
|
||||
echo " 总耗时: ${total_duration}秒"
|
||||
echo ""
|
||||
|
||||
if [ ${fail_count} -eq 0 ]; then
|
||||
echo "✓ 所有服务构建成功!"
|
||||
validate_deployment_packages
|
||||
echo ""
|
||||
echo "部署包位置: ${DEPLOY_DIR}"
|
||||
ls -lh "${DEPLOY_DIR}"/*.tar.gz
|
||||
else
|
||||
echo "✗ ${fail_count}个服务构建失败"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
```
|
||||
|
||||
## 部署包验证脚本
|
||||
|
||||
### 完整性检查 (scripts/validate-deployment.sh)
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 部署包完整性验证脚本
|
||||
|
||||
validate_package() {
|
||||
local tar_file=$1
|
||||
local service_name=$(basename "${tar_file}" .tar.gz)
|
||||
|
||||
echo "=== 验证部署包: ${service_name} ==="
|
||||
|
||||
# 1. 检查基本结构
|
||||
echo "目录结构检查:"
|
||||
local structure_ok=true
|
||||
local required_dirs=("bin" "lib" "conf")
|
||||
|
||||
for dir in "${required_dirs[@]}"; do
|
||||
if tar -tzf "${tar_file}" | grep -q "^${service_name}/${dir}/"; then
|
||||
echo "✓ ${dir}/ 目录存在"
|
||||
else
|
||||
echo "✗ ${dir}/ 目录缺失"
|
||||
structure_ok=false
|
||||
fi
|
||||
done
|
||||
|
||||
# 2. 检查必需文件
|
||||
echo "必需文件检查:"
|
||||
local required_files=(
|
||||
"bin/start.sh"
|
||||
"bin/stop.sh"
|
||||
"conf/env.properties"
|
||||
"conf/service.properties"
|
||||
"conf/application.yml"
|
||||
"lib/${service_name}*.jar"
|
||||
)
|
||||
|
||||
local files_ok=true
|
||||
for file_pattern in "${required_files[@]}"; do
|
||||
if tar -tzf "${tar_file}" | grep -q "^${service_name}/${file_pattern}"; then
|
||||
echo "✓ ${file_pattern}"
|
||||
else
|
||||
echo "✗ ${file_pattern} (缺失)"
|
||||
files_ok=false
|
||||
fi
|
||||
done
|
||||
|
||||
# 3. 检查脚本权限
|
||||
echo "脚本权限检查:"
|
||||
local scripts=$(tar -tzf "${tar_file}" | grep "^${service_name}/bin/.*\.sh$")
|
||||
for script in ${scripts}; do
|
||||
echo "✓ ${script} (可执行)"
|
||||
done
|
||||
|
||||
# 4. 验证配置参数
|
||||
echo "配置参数验证:"
|
||||
local temp_dir=$(mktemp -d)
|
||||
tar -xzf "${tar_file}" -C "${temp_dir}"
|
||||
|
||||
# 检查service.properties必需参数
|
||||
local service_conf="${temp_dir}/${service_name}/conf/service.properties"
|
||||
if [[ -f "${service_conf}" ]]; then
|
||||
local required_params=("APP_NAME" "MAIN_CLASS")
|
||||
for param in "${required_params[@]}"; do
|
||||
if grep -q "^${param}=" "${service_conf}"; then
|
||||
local value=$(grep "^${param}=" "${service_conf}" | cut -d'=' -f2 | xargs)
|
||||
echo "✓ ${param}=${value}"
|
||||
else
|
||||
echo "✗ 缺少参数: ${param}"
|
||||
files_ok=false
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 清理临时目录
|
||||
rm -rf "${temp_dir}"
|
||||
|
||||
# 最终结果
|
||||
if [[ "${structure_ok}" == true && "${files_ok}" == true ]]; then
|
||||
echo ""
|
||||
echo "✓ ${service_name} 部署包验证通过"
|
||||
return 0
|
||||
else
|
||||
echo ""
|
||||
echo "✗ ${service_name} 部署包验证失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
local deploy_dir="/home/along/MyCode/wanjiabuluo/fundplatform/deploy"
|
||||
|
||||
if [ ! -d "${deploy_dir}" ]; then
|
||||
echo "错误: 部署目录不存在 ${deploy_dir}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "扫描部署包: ${deploy_dir}"
|
||||
echo ""
|
||||
|
||||
local success_count=0
|
||||
local fail_count=0
|
||||
|
||||
for tar_file in "${deploy_dir}"/*.tar.gz; do
|
||||
if [[ -f "${tar_file}" ]]; then
|
||||
if validate_package "${tar_file}"; then
|
||||
((success_count++))
|
||||
else
|
||||
((fail_count++))
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
echo "=== 验证完成 ==="
|
||||
echo "成功: ${success_count}"
|
||||
echo "失败: ${fail_count}"
|
||||
|
||||
if [ ${fail_count} -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
```
|
||||
|
||||
## 故障排除指南
|
||||
|
||||
### 常见问题及解决方案
|
||||
|
||||
1. **配置文件缺失**
|
||||
```bash
|
||||
# 检查配置文件
|
||||
find . -name "env.properties"
|
||||
find . -name "service.properties"
|
||||
|
||||
# 验证必需参数
|
||||
grep -E "^(APP_NAME|MAIN_CLASS)=" fund-*/src/main/resources/service.properties
|
||||
```
|
||||
|
||||
2. **构建失败**
|
||||
```bash
|
||||
# 清理并重新构建
|
||||
mvn clean compile -X # 详细日志
|
||||
mvn dependency:tree # 检查依赖冲突
|
||||
```
|
||||
|
||||
3. **部署包结构异常**
|
||||
```bash
|
||||
# 检查tar.gz内容
|
||||
tar -tzf target/fund-sys.tar.gz | head -20
|
||||
|
||||
# 验证目录结构
|
||||
scripts/validate-deployment.sh
|
||||
```
|
||||
|
||||
4. **启动脚本问题**
|
||||
```bash
|
||||
# 测试配置加载
|
||||
bash -x bin/start.sh # 调试模式
|
||||
|
||||
# 检查环境变量
|
||||
echo $APP_NAME
|
||||
echo $MAIN_CLASS
|
||||
```
|
||||
|
||||
这套配置完全适配资金服务平台的架构特点,特别处理了统一配置和个性化配置的分离管理。
|
||||
Loading…
x
Reference in New Issue
Block a user