14 changed files with 1537 additions and 15 deletions
@ -0,0 +1,190 @@ |
|||||
|
# 数据库字段缺失问题修复指南 |
||||
|
|
||||
|
## 🐛 问题描述 |
||||
|
|
||||
|
错误信息: |
||||
|
``` |
||||
|
java.sql.SQLSyntaxErrorException: Unknown column 'goods_id' in 'field list' |
||||
|
``` |
||||
|
|
||||
|
**原因**: 数据库表 `shop_coupon_apply_item` 中缺少 `goods_id` 和 `category_id` 字段,但代码中尝试查询这些字段。 |
||||
|
|
||||
|
## 🔧 解决方案 |
||||
|
|
||||
|
### 方案一:执行数据库修复脚本(推荐) |
||||
|
|
||||
|
1. **备份数据库**(重要!) |
||||
|
```bash |
||||
|
mysqldump -u username -p database_name > backup_$(date +%Y%m%d_%H%M%S).sql |
||||
|
``` |
||||
|
|
||||
|
2. **执行修复脚本** |
||||
|
```bash |
||||
|
mysql -u username -p database_name < src/main/resources/sql/simple_fix_coupon_table.sql |
||||
|
``` |
||||
|
|
||||
|
或者手动执行以下SQL: |
||||
|
```sql |
||||
|
-- 添加缺失的字段 |
||||
|
ALTER TABLE shop_coupon_apply_item |
||||
|
ADD COLUMN goods_id INT(11) NULL COMMENT '商品ID' AFTER coupon_id; |
||||
|
|
||||
|
ALTER TABLE shop_coupon_apply_item |
||||
|
ADD COLUMN category_id INT(11) NULL COMMENT '分类ID' AFTER goods_id; |
||||
|
|
||||
|
-- 添加索引 |
||||
|
CREATE INDEX idx_coupon_apply_item_goods ON shop_coupon_apply_item(coupon_id, goods_id); |
||||
|
CREATE INDEX idx_coupon_apply_item_category ON shop_coupon_apply_item(coupon_id, category_id); |
||||
|
CREATE INDEX idx_coupon_apply_item_type ON shop_coupon_apply_item(coupon_id, type); |
||||
|
|
||||
|
-- 检查表结构 |
||||
|
DESCRIBE shop_coupon_apply_item; |
||||
|
``` |
||||
|
|
||||
|
### 方案二:临时代码修复(已实施) |
||||
|
|
||||
|
我已经修改了 `CouponStatusServiceImpl.java` 中的代码,添加了异常处理: |
||||
|
|
||||
|
```java |
||||
|
try { |
||||
|
// 尝试查询 goods_id 字段 |
||||
|
List<ShopCouponApplyItem> applyItems = shopCouponApplyItemService.list(...); |
||||
|
// 处理逻辑 |
||||
|
} catch (Exception e) { |
||||
|
log.warn("查询优惠券适用商品失败,可能是数据库字段不存在: {}", e.getMessage()); |
||||
|
// 如果查询失败,默认返回true(允许使用) |
||||
|
return true; |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## 📋 修复步骤 |
||||
|
|
||||
|
### 1. 立即修复(临时方案) |
||||
|
- ✅ 已修改代码添加异常处理 |
||||
|
- ✅ 使用 `pk` 字段作为临时的商品ID |
||||
|
- ✅ 查询失败时默认允许使用优惠券 |
||||
|
|
||||
|
### 2. 完整修复(推荐执行) |
||||
|
|
||||
|
#### 步骤1:停止应用 |
||||
|
```bash |
||||
|
# 如果使用Docker |
||||
|
docker-compose down |
||||
|
|
||||
|
# 或者直接停止Java进程 |
||||
|
pkill -f java |
||||
|
``` |
||||
|
|
||||
|
#### 步骤2:备份数据库 |
||||
|
```bash |
||||
|
mysqldump -u root -p your_database > backup_$(date +%Y%m%d_%H%M%S).sql |
||||
|
``` |
||||
|
|
||||
|
#### 步骤3:执行数据库修复 |
||||
|
```bash |
||||
|
mysql -u root -p your_database < src/main/resources/sql/simple_fix_coupon_table.sql |
||||
|
``` |
||||
|
|
||||
|
#### 步骤4:验证修复 |
||||
|
```sql |
||||
|
-- 检查表结构 |
||||
|
DESCRIBE shop_coupon_apply_item; |
||||
|
|
||||
|
-- 应该看到以下字段: |
||||
|
-- id, coupon_id, goods_id, category_id, type, pk, status, deleted, tenant_id, create_time, update_time |
||||
|
``` |
||||
|
|
||||
|
#### 步骤5:重启应用 |
||||
|
```bash |
||||
|
# 如果使用Docker |
||||
|
docker-compose up -d |
||||
|
|
||||
|
# 或者直接启动 |
||||
|
java -jar your-app.jar |
||||
|
``` |
||||
|
|
||||
|
## 🧪 测试验证 |
||||
|
|
||||
|
### 1. 检查API接口 |
||||
|
```bash |
||||
|
# 测试优惠券列表查询 |
||||
|
curl -X GET "http://localhost:9200/api/shop/user-coupon/my/available" |
||||
|
|
||||
|
# 测试优惠券验证 |
||||
|
curl -X POST "http://localhost:9200/api/shop/coupon-status/validate" \ |
||||
|
-H "Content-Type: application/json" \ |
||||
|
-d '{"userCouponId":1,"totalAmount":150.00,"goodsIds":[1,2,3]}' |
||||
|
``` |
||||
|
|
||||
|
### 2. 检查日志 |
||||
|
```bash |
||||
|
# 查看应用日志 |
||||
|
tail -f logs/application.log |
||||
|
|
||||
|
# 查找相关错误 |
||||
|
grep -i "goods_id\|SQLSyntaxErrorException" logs/application.log |
||||
|
``` |
||||
|
|
||||
|
## 📊 数据迁移(可选) |
||||
|
|
||||
|
如果表中已有数据,可能需要迁移: |
||||
|
|
||||
|
```sql |
||||
|
-- 如果原来使用 pk 字段存储商品ID |
||||
|
UPDATE shop_coupon_apply_item |
||||
|
SET goods_id = pk |
||||
|
WHERE type = 1 AND pk IS NOT NULL AND goods_id IS NULL; |
||||
|
|
||||
|
-- 如果原来使用其他字段存储分类ID |
||||
|
-- UPDATE shop_coupon_apply_item |
||||
|
-- SET category_id = some_other_field |
||||
|
-- WHERE type = 2 AND some_other_field IS NOT NULL AND category_id IS NULL; |
||||
|
``` |
||||
|
|
||||
|
## 🚨 注意事项 |
||||
|
|
||||
|
1. **数据备份**: 执行任何数据库修改前必须备份 |
||||
|
2. **停机时间**: 建议在低峰期执行修复 |
||||
|
3. **测试环境**: 先在测试环境验证修复效果 |
||||
|
4. **回滚计划**: 准备回滚方案以防出现问题 |
||||
|
|
||||
|
## 🔄 回滚方案 |
||||
|
|
||||
|
如果修复后出现问题,可以回滚: |
||||
|
|
||||
|
```sql |
||||
|
-- 删除新添加的字段 |
||||
|
ALTER TABLE shop_coupon_apply_item DROP COLUMN goods_id; |
||||
|
ALTER TABLE shop_coupon_apply_item DROP COLUMN category_id; |
||||
|
|
||||
|
-- 删除新添加的索引 |
||||
|
DROP INDEX idx_coupon_apply_item_goods ON shop_coupon_apply_item; |
||||
|
DROP INDEX idx_coupon_apply_item_category ON shop_coupon_apply_item; |
||||
|
DROP INDEX idx_coupon_apply_item_type ON shop_coupon_apply_item; |
||||
|
``` |
||||
|
|
||||
|
或者直接恢复备份: |
||||
|
```bash |
||||
|
mysql -u root -p your_database < backup_20250115_143000.sql |
||||
|
``` |
||||
|
|
||||
|
## ✅ 修复完成检查清单 |
||||
|
|
||||
|
- [ ] 数据库已备份 |
||||
|
- [ ] 执行了字段添加脚本 |
||||
|
- [ ] 验证了表结构正确 |
||||
|
- [ ] 重启了应用 |
||||
|
- [ ] 测试了API接口正常 |
||||
|
- [ ] 检查了应用日志无错误 |
||||
|
- [ ] 验证了优惠券功能正常 |
||||
|
|
||||
|
## 📞 技术支持 |
||||
|
|
||||
|
如果在修复过程中遇到问题,请: |
||||
|
|
||||
|
1. 检查数据库连接和权限 |
||||
|
2. 确认SQL语法与MySQL版本兼容 |
||||
|
3. 查看详细的错误日志 |
||||
|
4. 如有必要,联系技术支持团队 |
||||
|
|
||||
|
修复完成后,优惠券状态管理功能应该可以正常使用! |
@ -0,0 +1,212 @@ |
|||||
|
# 支付环境隔离解决方案 |
||||
|
|
||||
|
## 🎯 问题描述 |
||||
|
|
||||
|
**现状问题**: |
||||
|
- 开发调试时需要修改支付回调地址为本地地址 |
||||
|
- 修改后影响线上生产环境的正常使用 |
||||
|
- 缺乏开发和生产环境的有效隔离机制 |
||||
|
|
||||
|
## 💡 解决方案概览 |
||||
|
|
||||
|
我为您提供了5种解决方案,可以单独使用或组合使用: |
||||
|
|
||||
|
### 方案一:创建开发专用租户(推荐)✨ |
||||
|
- 创建独立的开发租户(ID: 9999) |
||||
|
- 配置专用的支付参数和回调地址 |
||||
|
- 完全隔离开发和生产环境 |
||||
|
|
||||
|
### 方案二:环境感知的支付配置服务 |
||||
|
- 根据 `spring.profiles.active` 自动切换回调地址 |
||||
|
- 开发环境自动使用本地回调,生产环境使用线上回调 |
||||
|
- 无需手动修改配置 |
||||
|
|
||||
|
### 方案三:配置文件环境隔离 |
||||
|
- 在配置文件中定义不同环境的回调地址 |
||||
|
- 支持灵活的环境配置管理 |
||||
|
|
||||
|
### 方案四:开发环境管理工具 |
||||
|
- 提供专用的开发环境管理接口 |
||||
|
- 支持一键切换和恢复回调地址 |
||||
|
- 仅在开发环境启用 |
||||
|
|
||||
|
### 方案五:多租户配置隔离 |
||||
|
- 利用现有的多租户架构 |
||||
|
- 为不同租户配置不同的支付参数 |
||||
|
|
||||
|
## 🚀 快速实施指南 |
||||
|
|
||||
|
### 步骤1:执行数据库脚本(推荐) |
||||
|
|
||||
|
```bash |
||||
|
# 创建开发专用租户和配置 |
||||
|
mysql -u root -p your_database < src/main/resources/sql/create_dev_tenant_payment.sql |
||||
|
``` |
||||
|
|
||||
|
这将创建: |
||||
|
- 开发专用租户(ID: 9999) |
||||
|
- 开发环境支付配置(使用本地回调地址) |
||||
|
- 开发测试用户 |
||||
|
|
||||
|
### 步骤2:配置环境感知服务 |
||||
|
|
||||
|
已创建的服务会自动: |
||||
|
- 检测当前运行环境 |
||||
|
- 根据环境自动调整回调地址 |
||||
|
- 开发环境:`http://frps-10550.s209.websoft.top/api/shop/shop-order/notify` |
||||
|
- 生产环境:`https://cms-api.websoft.top/api/shop/shop-order/notify` |
||||
|
|
||||
|
### 步骤3:使用开发环境管理工具 |
||||
|
|
||||
|
开发环境下可以访问以下接口: |
||||
|
|
||||
|
```bash |
||||
|
# 查看环境信息 |
||||
|
GET /api/dev/environment/info |
||||
|
|
||||
|
# 查看支付配置 |
||||
|
GET /api/dev/payment/config/0 |
||||
|
|
||||
|
# 切换回调地址 |
||||
|
POST /api/dev/payment/switch-notify-url |
||||
|
{ |
||||
|
"notifyUrl": "http://your-local-address/api/shop/shop-order/notify", |
||||
|
"payType": "0" |
||||
|
} |
||||
|
|
||||
|
# 重置为生产环境 |
||||
|
POST /api/dev/payment/reset-to-prod?payType=0 |
||||
|
|
||||
|
# 获取使用指南 |
||||
|
GET /api/dev/guide |
||||
|
``` |
||||
|
|
||||
|
## 📋 使用方式对比 |
||||
|
|
||||
|
| 方案 | 优点 | 缺点 | 适用场景 | |
||||
|
|------|------|------|----------| |
||||
|
| 开发专用租户 | 完全隔离,不影响生产 | 需要创建额外数据 | 团队开发,长期使用 | |
||||
|
| 环境感知服务 | 自动切换,无需手动操作 | 需要代码改动 | 自动化程度高的项目 | |
||||
|
| 配置文件隔离 | 配置灵活,易于管理 | 需要重启应用 | 配置驱动的项目 | |
||||
|
| 开发管理工具 | 操作简单,功能丰富 | 仅开发环境可用 | 频繁调试的场景 | |
||||
|
| 多租户隔离 | 利用现有架构 | 依赖租户体系 | 已有多租户的系统 | |
||||
|
|
||||
|
## 🔧 配置示例 |
||||
|
|
||||
|
### 开发环境配置 (application-dev.yml) |
||||
|
```yaml |
||||
|
payment: |
||||
|
dev: |
||||
|
notify-url: "http://frps-10550.s209.websoft.top/api/shop/shop-order/notify" |
||||
|
environment-aware: true |
||||
|
``` |
||||
|
|
||||
|
### 生产环境配置 (application-prod.yml) |
||||
|
```yaml |
||||
|
payment: |
||||
|
prod: |
||||
|
notify-url: "https://cms-api.websoft.top/api/shop/shop-order/notify" |
||||
|
environment-aware: false |
||||
|
``` |
||||
|
|
||||
|
## 🧪 测试验证 |
||||
|
|
||||
|
### 1. 验证环境感知功能 |
||||
|
```bash |
||||
|
# 检查当前环境 |
||||
|
curl -X GET "http://localhost:9200/api/dev/environment/info" |
||||
|
|
||||
|
# 检查支付配置 |
||||
|
curl -X GET "http://localhost:9200/api/dev/payment/config/0" |
||||
|
``` |
||||
|
|
||||
|
### 2. 验证回调地址切换 |
||||
|
```bash |
||||
|
# 切换到本地回调 |
||||
|
curl -X POST "http://localhost:9200/api/dev/payment/switch-notify-url" \ |
||||
|
-H "Content-Type: application/json" \ |
||||
|
-d '{"notifyUrl":"http://localhost:8080/api/shop/shop-order/notify","payType":"0"}' |
||||
|
|
||||
|
# 重置为生产回调 |
||||
|
curl -X POST "http://localhost:9200/api/dev/payment/reset-to-prod?payType=0" |
||||
|
``` |
||||
|
|
||||
|
## 🎨 最佳实践建议 |
||||
|
|
||||
|
### 推荐组合方案 |
||||
|
|
||||
|
**方案A:完全隔离(推荐)** |
||||
|
1. 创建开发专用租户 |
||||
|
2. 配置开发环境支付参数 |
||||
|
3. 使用开发租户进行所有测试 |
||||
|
|
||||
|
**方案B:自动化切换** |
||||
|
1. 部署环境感知服务 |
||||
|
2. 配置环境相关参数 |
||||
|
3. 代码自动根据环境切换 |
||||
|
|
||||
|
**方案C:手动管理** |
||||
|
1. 使用开发环境管理工具 |
||||
|
2. 调试时切换回调地址 |
||||
|
3. 完成后恢复生产配置 |
||||
|
|
||||
|
### 开发流程建议 |
||||
|
|
||||
|
1. **开发阶段**:使用开发租户或本地回调地址 |
||||
|
2. **测试阶段**:使用测试环境配置 |
||||
|
3. **上线前**:确认生产环境配置正确 |
||||
|
4. **上线后**:验证生产环境支付功能 |
||||
|
|
||||
|
## 🚨 注意事项 |
||||
|
|
||||
|
### 安全考虑 |
||||
|
- 开发环境管理接口仅在开发环境启用 |
||||
|
- 生产环境不会加载开发相关的控制器 |
||||
|
- 敏感配置信息需要妥善保护 |
||||
|
|
||||
|
### 数据一致性 |
||||
|
- 开发租户数据与生产数据隔离 |
||||
|
- 定期清理开发环境测试数据 |
||||
|
- 避免开发数据污染生产环境 |
||||
|
|
||||
|
### 团队协作 |
||||
|
- 统一开发环境配置标准 |
||||
|
- 文档化配置变更流程 |
||||
|
- 建立配置变更审核机制 |
||||
|
|
||||
|
## 🔄 回滚方案 |
||||
|
|
||||
|
如果需要回滚到原有方式: |
||||
|
|
||||
|
```sql |
||||
|
-- 删除开发租户(可选) |
||||
|
DELETE FROM sys_tenant WHERE tenant_id = 9999; |
||||
|
DELETE FROM sys_payment WHERE tenant_id = 9999; |
||||
|
DELETE FROM sys_user WHERE tenant_id = 9999; |
||||
|
|
||||
|
-- 恢复原有支付配置 |
||||
|
UPDATE sys_payment |
||||
|
SET notify_url = 'https://cms-api.websoft.top/api/shop/shop-order/notify' |
||||
|
WHERE tenant_id = 1; |
||||
|
``` |
||||
|
|
||||
|
## ✅ 实施检查清单 |
||||
|
|
||||
|
- [ ] 执行了数据库脚本创建开发租户 |
||||
|
- [ ] 配置了环境感知服务 |
||||
|
- [ ] 测试了开发环境管理接口 |
||||
|
- [ ] 验证了自动环境切换功能 |
||||
|
- [ ] 确认了生产环境配置正确 |
||||
|
- [ ] 建立了开发流程规范 |
||||
|
- [ ] 培训了团队成员使用方法 |
||||
|
|
||||
|
## 📞 技术支持 |
||||
|
|
||||
|
如果在实施过程中遇到问题: |
||||
|
|
||||
|
1. 检查日志中的环境检测信息 |
||||
|
2. 验证配置文件中的环境参数 |
||||
|
3. 确认数据库中的租户和支付配置 |
||||
|
4. 测试开发环境管理接口功能 |
||||
|
|
||||
|
实施完成后,您就可以在不影响生产环境的情况下进行支付功能的开发和调试了! |
@ -0,0 +1,176 @@ |
|||||
|
# 生产环境安全配置指南 |
||||
|
|
||||
|
## 🚨 重要警告 |
||||
|
|
||||
|
**原始的 `create_dev_tenant_payment.sql` 脚本不要在生产数据库执行!** |
||||
|
|
||||
|
该脚本包含测试数据,可能会影响生产环境。 |
||||
|
|
||||
|
## ✅ 安全的生产环境配置方案 |
||||
|
|
||||
|
### 方案一:使用后台管理界面(推荐) |
||||
|
|
||||
|
1. **登录后台管理系统** |
||||
|
2. **进入支付配置页面** |
||||
|
3. **创建新的支付配置**: |
||||
|
- 名称:`微信支付-开发环境` |
||||
|
- 类型:微信支付 |
||||
|
- 回调地址:`http://frps-10550.s209.websoft.top/api/shop/shop-order/notify` |
||||
|
- 其他参数:复制现有生产配置 |
||||
|
|
||||
|
### 方案二:使用API接口 |
||||
|
|
||||
|
```bash |
||||
|
# 1. 获取当前配置 |
||||
|
curl -X GET "https://your-domain.com/api/payment/list" \ |
||||
|
-H "Authorization: Bearer YOUR_TOKEN" |
||||
|
|
||||
|
# 2. 创建开发配置 |
||||
|
curl -X POST "https://your-domain.com/api/payment" \ |
||||
|
-H "Content-Type: application/json" \ |
||||
|
-H "Authorization: Bearer YOUR_TOKEN" \ |
||||
|
-d '{ |
||||
|
"name": "微信支付-开发环境", |
||||
|
"type": 0, |
||||
|
"appId": "YOUR_DEV_APP_ID", |
||||
|
"mchId": "YOUR_DEV_MCH_ID", |
||||
|
"notifyUrl": "http://frps-10550.s209.websoft.top/api/shop/shop-order/notify", |
||||
|
"environment": "dev" |
||||
|
}' |
||||
|
``` |
||||
|
|
||||
|
### 方案三:执行安全的SQL脚本 |
||||
|
|
||||
|
如果必须使用SQL,请使用我刚创建的安全版本: |
||||
|
|
||||
|
```bash |
||||
|
# 1. 先备份数据库 |
||||
|
mysqldump -u root -p your_database > backup_$(date +%Y%m%d_%H%M%S).sql |
||||
|
|
||||
|
# 2. 执行安全脚本 |
||||
|
mysql -u root -p your_database < src/main/resources/sql/production_safe_payment_config.sql |
||||
|
|
||||
|
# 3. 根据脚本输出的模板,手动创建开发配置 |
||||
|
``` |
||||
|
|
||||
|
## 🔧 推荐的实施步骤 |
||||
|
|
||||
|
### 步骤1:备份现有配置 |
||||
|
|
||||
|
```sql |
||||
|
-- 备份当前支付配置 |
||||
|
CREATE TABLE sys_payment_backup_$(date +%Y%m%d) AS |
||||
|
SELECT * FROM sys_payment WHERE status = 1; |
||||
|
``` |
||||
|
|
||||
|
### 步骤2:查看当前配置 |
||||
|
|
||||
|
```sql |
||||
|
-- 查看现有支付配置 |
||||
|
SELECT id, name, type, notify_url, tenant_id |
||||
|
FROM sys_payment |
||||
|
WHERE status = 1 AND deleted = 0; |
||||
|
``` |
||||
|
|
||||
|
### 步骤3:创建开发配置 |
||||
|
|
||||
|
**选择以下方式之一**: |
||||
|
|
||||
|
#### 方式A:通过后台界面 |
||||
|
1. 复制现有生产配置 |
||||
|
2. 修改名称为"开发环境" |
||||
|
3. 修改回调地址为本地地址 |
||||
|
|
||||
|
#### 方式B:通过SQL(谨慎使用) |
||||
|
```sql |
||||
|
-- 基于现有配置创建开发版本 |
||||
|
INSERT INTO sys_payment ( |
||||
|
name, type, code, app_id, mch_id, api_key, |
||||
|
notify_url, tenant_id, status, deleted, create_time, update_time |
||||
|
) |
||||
|
SELECT |
||||
|
CONCAT(name, '-开发环境'), |
||||
|
type, |
||||
|
CONCAT(code, '_dev'), |
||||
|
app_id, |
||||
|
mch_id, |
||||
|
api_key, |
||||
|
'http://frps-10550.s209.websoft.top/api/shop/shop-order/notify', |
||||
|
tenant_id, |
||||
|
0, -- 先设为禁用状态 |
||||
|
0, |
||||
|
NOW(), |
||||
|
NOW() |
||||
|
FROM sys_payment |
||||
|
WHERE type = 0 AND status = 1 AND deleted = 0 |
||||
|
LIMIT 1; |
||||
|
``` |
||||
|
|
||||
|
### 步骤4:测试和验证 |
||||
|
|
||||
|
```bash |
||||
|
# 测试开发环境配置 |
||||
|
curl -X GET "http://localhost:9200/api/dev/payment/config/0" |
||||
|
|
||||
|
# 验证回调地址 |
||||
|
curl -X POST "http://frps-10550.s209.websoft.top/api/shop/shop-order/notify" \ |
||||
|
-d "test=1" |
||||
|
``` |
||||
|
|
||||
|
## 🛡️ 安全检查清单 |
||||
|
|
||||
|
- [ ] 已备份生产数据库 |
||||
|
- [ ] 确认当前数据库环境 |
||||
|
- [ ] 使用安全的配置方法 |
||||
|
- [ ] 测试开发配置不影响生产 |
||||
|
- [ ] 验证回调地址可访问 |
||||
|
- [ ] 建立配置恢复机制 |
||||
|
|
||||
|
## 🔄 快速切换方案 |
||||
|
|
||||
|
### 开发时切换到本地回调 |
||||
|
|
||||
|
```sql |
||||
|
-- 临时修改(记录原始值) |
||||
|
UPDATE sys_payment |
||||
|
SET notify_url = 'http://frps-10550.s209.websoft.top/api/shop/shop-order/notify' |
||||
|
WHERE id = YOUR_PAYMENT_CONFIG_ID; |
||||
|
``` |
||||
|
|
||||
|
### 完成后恢复生产回调 |
||||
|
|
||||
|
```sql |
||||
|
-- 恢复生产配置 |
||||
|
UPDATE sys_payment |
||||
|
SET notify_url = 'https://cms-api.websoft.top/api/shop/shop-order/notify' |
||||
|
WHERE id = YOUR_PAYMENT_CONFIG_ID; |
||||
|
``` |
||||
|
|
||||
|
## 🚀 最佳实践 |
||||
|
|
||||
|
1. **使用环境感知服务**:让代码自动根据环境切换 |
||||
|
2. **创建专用开发配置**:避免修改生产配置 |
||||
|
3. **使用配置管理工具**:通过界面而非SQL操作 |
||||
|
4. **建立回滚机制**:确保可以快速恢复 |
||||
|
5. **团队协作规范**:统一配置管理流程 |
||||
|
|
||||
|
## ❌ 避免的操作 |
||||
|
|
||||
|
- ❌ 直接在生产库执行包含测试数据的脚本 |
||||
|
- ❌ 修改生产配置进行开发调试 |
||||
|
- ❌ 在生产环境创建测试租户 |
||||
|
- ❌ 不备份就修改重要配置 |
||||
|
- ❌ 忘记恢复生产环境配置 |
||||
|
|
||||
|
## 📞 如果出现问题 |
||||
|
|
||||
|
1. **立即停止操作** |
||||
|
2. **检查数据库备份** |
||||
|
3. **恢复原始配置**: |
||||
|
```sql |
||||
|
-- 从备份恢复 |
||||
|
INSERT INTO sys_payment SELECT * FROM sys_payment_backup_YYYYMMDD; |
||||
|
``` |
||||
|
4. **联系技术支持** |
||||
|
|
||||
|
记住:**安全第一,谨慎操作!** 🛡️ |
@ -0,0 +1,236 @@ |
|||||
|
package com.gxwebsoft.common.core.controller; |
||||
|
|
||||
|
import com.gxwebsoft.common.core.service.EnvironmentAwarePaymentService; |
||||
|
import com.gxwebsoft.common.core.service.PaymentCacheService; |
||||
|
import com.gxwebsoft.common.core.web.ApiResult; |
||||
|
import com.gxwebsoft.common.core.web.BaseController; |
||||
|
import com.gxwebsoft.common.system.entity.Payment; |
||||
|
import com.gxwebsoft.common.system.service.PaymentService; |
||||
|
import io.swagger.v3.oas.annotations.Operation; |
||||
|
import io.swagger.v3.oas.annotations.tags.Tag; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* 开发环境管理控制器 |
||||
|
* 仅在开发环境启用,用于管理开发调试配置 |
||||
|
* |
||||
|
* @author WebSoft |
||||
|
* @since 2025-01-15 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Tag(name = "开发环境管理") |
||||
|
@RestController |
||||
|
@RequestMapping("/api/dev") |
||||
|
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev") |
||||
|
public class DevEnvironmentController extends BaseController { |
||||
|
|
||||
|
@Autowired |
||||
|
private EnvironmentAwarePaymentService environmentAwarePaymentService; |
||||
|
|
||||
|
@Autowired |
||||
|
private PaymentCacheService paymentCacheService; |
||||
|
|
||||
|
@Autowired |
||||
|
private PaymentService paymentService; |
||||
|
|
||||
|
@Value("${spring.profiles.active:dev}") |
||||
|
private String activeProfile; |
||||
|
|
||||
|
@Operation(summary = "获取当前环境信息") |
||||
|
@GetMapping("/environment/info") |
||||
|
public ApiResult<Map<String, Object>> getEnvironmentInfo() { |
||||
|
Map<String, Object> info = new HashMap<>(); |
||||
|
info.put("activeProfile", activeProfile); |
||||
|
info.put("isDevelopment", environmentAwarePaymentService.isDevelopmentEnvironment()); |
||||
|
info.put("isProduction", environmentAwarePaymentService.isProductionEnvironment()); |
||||
|
info.put("currentEnvironment", environmentAwarePaymentService.getCurrentEnvironment()); |
||||
|
|
||||
|
return success("获取成功", info); |
||||
|
} |
||||
|
|
||||
|
@Operation(summary = "获取环境感知的支付配置") |
||||
|
@GetMapping("/payment/config/{payType}") |
||||
|
public ApiResult<Map<String, Object>> getPaymentConfig(@PathVariable Integer payType) { |
||||
|
try { |
||||
|
Integer tenantId = getTenantId(); |
||||
|
|
||||
|
// 获取原始配置
|
||||
|
Payment originalConfig = paymentCacheService.getPaymentConfig(payType, tenantId); |
||||
|
|
||||
|
// 获取环境感知配置
|
||||
|
Payment envConfig = environmentAwarePaymentService.getEnvironmentAwarePaymentConfig(payType, tenantId); |
||||
|
|
||||
|
Map<String, Object> result = new HashMap<>(); |
||||
|
result.put("tenantId", tenantId); |
||||
|
result.put("payType", payType); |
||||
|
result.put("environment", activeProfile); |
||||
|
result.put("originalConfig", originalConfig); |
||||
|
result.put("environmentAwareConfig", envConfig); |
||||
|
|
||||
|
if (originalConfig != null && envConfig != null) { |
||||
|
result.put("notifyUrlChanged", !originalConfig.getNotifyUrl().equals(envConfig.getNotifyUrl())); |
||||
|
result.put("originalNotifyUrl", originalConfig.getNotifyUrl()); |
||||
|
result.put("environmentNotifyUrl", envConfig.getNotifyUrl()); |
||||
|
} |
||||
|
|
||||
|
return success("获取成功", result); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("获取支付配置失败", e); |
||||
|
return fail("获取失败: " + e.getMessage(),null); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Operation(summary = "切换开发环境回调地址") |
||||
|
@PostMapping("/payment/switch-notify-url") |
||||
|
public ApiResult<?> switchNotifyUrl(@RequestBody Map<String, String> request) { |
||||
|
try { |
||||
|
String newNotifyUrl = request.get("notifyUrl"); |
||||
|
Integer payType = Integer.valueOf(request.getOrDefault("payType", "0")); |
||||
|
|
||||
|
if (newNotifyUrl == null || newNotifyUrl.trim().isEmpty()) { |
||||
|
return fail("回调地址不能为空"); |
||||
|
} |
||||
|
|
||||
|
Integer tenantId = getTenantId(); |
||||
|
|
||||
|
// 获取当前配置
|
||||
|
Payment payment = paymentCacheService.getPaymentConfig(payType, tenantId); |
||||
|
if (payment == null) { |
||||
|
return fail("未找到支付配置"); |
||||
|
} |
||||
|
|
||||
|
// 更新回调地址
|
||||
|
payment.setNotifyUrl(newNotifyUrl); |
||||
|
|
||||
|
// 更新数据库
|
||||
|
boolean updated = paymentService.updateById(payment); |
||||
|
|
||||
|
if (updated) { |
||||
|
// 清除缓存,强制重新加载
|
||||
|
paymentCacheService.removePaymentConfig(payType.toString(), tenantId); |
||||
|
|
||||
|
log.info("开发环境回调地址已更新: {} -> {}", payment.getNotifyUrl(), newNotifyUrl); |
||||
|
|
||||
|
Map<String, Object> result = new HashMap<>(); |
||||
|
result.put("oldNotifyUrl", payment.getNotifyUrl()); |
||||
|
result.put("newNotifyUrl", newNotifyUrl); |
||||
|
result.put("payType", payType); |
||||
|
result.put("tenantId", tenantId); |
||||
|
|
||||
|
return success("回调地址更新成功", result); |
||||
|
} else { |
||||
|
return fail("更新失败"); |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("切换回调地址失败", e); |
||||
|
return fail("切换失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Operation(summary = "重置为生产环境回调地址") |
||||
|
@PostMapping("/payment/reset-to-prod") |
||||
|
public ApiResult<?> resetToProdNotifyUrl(@RequestParam(defaultValue = "0") Integer payType) { |
||||
|
try { |
||||
|
Integer tenantId = getTenantId(); |
||||
|
|
||||
|
// 获取当前配置
|
||||
|
Payment payment = paymentCacheService.getPaymentConfig(payType, tenantId); |
||||
|
if (payment == null) { |
||||
|
return fail("未找到支付配置"); |
||||
|
} |
||||
|
|
||||
|
// 设置为生产环境回调地址
|
||||
|
String prodNotifyUrl = "https://cms-api.websoft.top/api/shop/shop-order/notify"; |
||||
|
String oldNotifyUrl = payment.getNotifyUrl(); |
||||
|
|
||||
|
payment.setNotifyUrl(prodNotifyUrl); |
||||
|
|
||||
|
// 更新数据库
|
||||
|
boolean updated = paymentService.updateById(payment); |
||||
|
|
||||
|
if (updated) { |
||||
|
// 清除缓存
|
||||
|
paymentCacheService.removePaymentConfig(payType.toString(), tenantId); |
||||
|
|
||||
|
log.info("回调地址已重置为生产环境: {} -> {}", oldNotifyUrl, prodNotifyUrl); |
||||
|
|
||||
|
Map<String, Object> result = new HashMap<>(); |
||||
|
result.put("oldNotifyUrl", oldNotifyUrl); |
||||
|
result.put("newNotifyUrl", prodNotifyUrl); |
||||
|
result.put("payType", payType); |
||||
|
result.put("tenantId", tenantId); |
||||
|
|
||||
|
return success("已重置为生产环境回调地址", result); |
||||
|
} else { |
||||
|
return fail("重置失败"); |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("重置回调地址失败", e); |
||||
|
return fail("重置失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Operation(summary = "清除支付配置缓存") |
||||
|
@PostMapping("/payment/clear-cache") |
||||
|
public ApiResult<?> clearPaymentCache(@RequestParam(defaultValue = "0") Integer payType) { |
||||
|
try { |
||||
|
Integer tenantId = getTenantId(); |
||||
|
|
||||
|
paymentCacheService.removePaymentConfig(payType.toString(), tenantId); |
||||
|
|
||||
|
log.info("支付配置缓存已清除: payType={}, tenantId={}", payType, tenantId); |
||||
|
|
||||
|
return success("缓存清除成功"); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("清除缓存失败", e); |
||||
|
return fail("清除失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Operation(summary = "获取开发环境使用指南") |
||||
|
@GetMapping("/guide") |
||||
|
public ApiResult<Map<String, Object>> getDevGuide() { |
||||
|
Map<String, Object> guide = new HashMap<>(); |
||||
|
|
||||
|
guide.put("title", "开发环境支付调试指南"); |
||||
|
guide.put("environment", activeProfile); |
||||
|
|
||||
|
Map<String, String> steps = new HashMap<>(); |
||||
|
steps.put("step1", "使用 /api/dev/payment/switch-notify-url 切换到本地回调地址"); |
||||
|
steps.put("step2", "进行支付功能调试和测试"); |
||||
|
steps.put("step3", "调试完成后使用 /api/dev/payment/reset-to-prod 恢复生产环境配置"); |
||||
|
steps.put("step4", "或者直接在后台管理界面修改回调地址"); |
||||
|
|
||||
|
guide.put("steps", steps); |
||||
|
|
||||
|
Map<String, String> apis = new HashMap<>(); |
||||
|
apis.put("环境信息", "GET /api/dev/environment/info"); |
||||
|
apis.put("查看配置", "GET /api/dev/payment/config/{payType}"); |
||||
|
apis.put("切换回调", "POST /api/dev/payment/switch-notify-url"); |
||||
|
apis.put("重置生产", "POST /api/dev/payment/reset-to-prod"); |
||||
|
apis.put("清除缓存", "POST /api/dev/payment/clear-cache"); |
||||
|
|
||||
|
guide.put("apis", apis); |
||||
|
|
||||
|
Map<String, String> tips = new HashMap<>(); |
||||
|
tips.put("tip1", "此控制器仅在开发环境启用"); |
||||
|
tips.put("tip2", "生产环境不会加载这些接口"); |
||||
|
tips.put("tip3", "建议使用环境感知服务自动切换"); |
||||
|
tips.put("tip4", "记得在调试完成后恢复生产配置"); |
||||
|
|
||||
|
guide.put("tips", tips); |
||||
|
|
||||
|
return success("获取成功", guide); |
||||
|
} |
||||
|
} |
@ -0,0 +1,143 @@ |
|||||
|
package com.gxwebsoft.common.core.service; |
||||
|
|
||||
|
import com.gxwebsoft.common.system.entity.Payment; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
/** |
||||
|
* 环境感知的支付配置服务 |
||||
|
* 根据不同环境自动切换支付回调地址 |
||||
|
* |
||||
|
* @author WebSoft |
||||
|
* @since 2025-01-15 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class EnvironmentAwarePaymentService { |
||||
|
|
||||
|
@Autowired |
||||
|
private PaymentCacheService paymentCacheService; |
||||
|
|
||||
|
@Value("${spring.profiles.active:dev}") |
||||
|
private String activeProfile; |
||||
|
|
||||
|
@Value("${config.server-url:}") |
||||
|
private String serverUrl; |
||||
|
|
||||
|
// 开发环境回调地址配置
|
||||
|
@Value("${payment.dev.notify-url:http://frps-10550.s209.websoft.top/api/shop/shop-order/notify}") |
||||
|
private String devNotifyUrl; |
||||
|
|
||||
|
// 生产环境回调地址配置
|
||||
|
@Value("${payment.prod.notify-url:https://cms-api.websoft.top/api/shop/shop-order/notify}") |
||||
|
private String prodNotifyUrl; |
||||
|
|
||||
|
/** |
||||
|
* 获取环境感知的支付配置 |
||||
|
* 根据当前环境自动调整回调地址 |
||||
|
* |
||||
|
* @param payType 支付类型 |
||||
|
* @param tenantId 租户ID |
||||
|
* @return 支付配置 |
||||
|
*/ |
||||
|
public Payment getEnvironmentAwarePaymentConfig(Integer payType, Integer tenantId) { |
||||
|
// 获取原始支付配置
|
||||
|
Payment payment = paymentCacheService.getPaymentConfig(payType, tenantId); |
||||
|
|
||||
|
if (payment == null) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 根据环境调整回调地址
|
||||
|
Payment envPayment = clonePayment(payment); |
||||
|
String notifyUrl = getEnvironmentNotifyUrl(); |
||||
|
|
||||
|
log.info("环境感知支付配置 - 环境: {}, 原始回调: {}, 调整后回调: {}", |
||||
|
activeProfile, payment.getNotifyUrl(), notifyUrl); |
||||
|
|
||||
|
envPayment.setNotifyUrl(notifyUrl); |
||||
|
|
||||
|
return envPayment; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据当前环境获取回调地址 |
||||
|
*/ |
||||
|
private String getEnvironmentNotifyUrl() { |
||||
|
if ("dev".equals(activeProfile) || "test".equals(activeProfile)) { |
||||
|
// 开发/测试环境使用本地回调地址
|
||||
|
return devNotifyUrl; |
||||
|
} else if ("prod".equals(activeProfile)) { |
||||
|
// 生产环境使用生产回调地址
|
||||
|
return prodNotifyUrl; |
||||
|
} else { |
||||
|
// 默认使用配置的服务器地址
|
||||
|
return serverUrl + "/shop/shop-order/notify"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 克隆支付配置对象 |
||||
|
*/ |
||||
|
private Payment clonePayment(Payment original) { |
||||
|
Payment cloned = new Payment(); |
||||
|
cloned.setId(original.getId()); |
||||
|
cloned.setName(original.getName()); |
||||
|
cloned.setType(original.getType()); |
||||
|
cloned.setCode(original.getCode()); |
||||
|
cloned.setImage(original.getImage()); |
||||
|
cloned.setWechatType(original.getWechatType()); |
||||
|
cloned.setAppId(original.getAppId()); |
||||
|
cloned.setMchId(original.getMchId()); |
||||
|
cloned.setApiKey(original.getApiKey()); |
||||
|
cloned.setApiclientCert(original.getApiclientCert()); |
||||
|
cloned.setApiclientKey(original.getApiclientKey()); |
||||
|
cloned.setPubKey(original.getPubKey()); |
||||
|
cloned.setPubKeyId(original.getPubKeyId()); |
||||
|
cloned.setMerchantSerialNumber(original.getMerchantSerialNumber()); |
||||
|
cloned.setNotifyUrl(original.getNotifyUrl()); // 这个会被后续覆盖
|
||||
|
cloned.setComments(original.getComments()); |
||||
|
cloned.setSortNumber(original.getSortNumber()); |
||||
|
cloned.setStatus(original.getStatus()); |
||||
|
cloned.setDeleted(original.getDeleted()); |
||||
|
cloned.setTenantId(original.getTenantId()); |
||||
|
return cloned; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取微信支付配置(环境感知) |
||||
|
*/ |
||||
|
public Payment getWechatPayConfig(Integer tenantId) { |
||||
|
return getEnvironmentAwarePaymentConfig(0, tenantId); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取支付宝配置(环境感知) |
||||
|
*/ |
||||
|
public Payment getAlipayConfig(Integer tenantId) { |
||||
|
return getEnvironmentAwarePaymentConfig(1, tenantId); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查当前环境 |
||||
|
*/ |
||||
|
public String getCurrentEnvironment() { |
||||
|
return activeProfile; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 是否为开发环境 |
||||
|
*/ |
||||
|
public boolean isDevelopmentEnvironment() { |
||||
|
return "dev".equals(activeProfile) || "test".equals(activeProfile); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 是否为生产环境 |
||||
|
*/ |
||||
|
public boolean isProductionEnvironment() { |
||||
|
return "prod".equals(activeProfile); |
||||
|
} |
||||
|
} |
@ -0,0 +1,206 @@ |
|||||
|
-- 创建开发专用租户和支付配置 |
||||
|
-- 用于隔离开发环境和生产环境的支付回调地址 |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 1. 创建开发专用租户(如果不存在) |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 检查是否已存在开发租户 |
||||
|
SELECT 'Checking for dev tenant...' as status; |
||||
|
|
||||
|
-- 插入开发租户(租户ID使用 9999 避免与生产冲突) |
||||
|
INSERT IGNORE INTO sys_tenant ( |
||||
|
tenant_id, |
||||
|
tenant_name, |
||||
|
tenant_code, |
||||
|
contact_person, |
||||
|
contact_phone, |
||||
|
contact_email, |
||||
|
status, |
||||
|
deleted, |
||||
|
create_time, |
||||
|
update_time, |
||||
|
comments |
||||
|
) VALUES ( |
||||
|
9999, |
||||
|
'开发测试租户', |
||||
|
'DEV_TENANT', |
||||
|
'开发者', |
||||
|
'13800000000', |
||||
|
'dev@websoft.top', |
||||
|
1, |
||||
|
0, |
||||
|
NOW(), |
||||
|
NOW(), |
||||
|
'专用于开发环境测试,不影响生产环境' |
||||
|
); |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 2. 创建开发环境专用支付配置 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 微信支付开发配置 |
||||
|
INSERT IGNORE INTO sys_payment ( |
||||
|
name, |
||||
|
type, |
||||
|
code, |
||||
|
image, |
||||
|
wechat_type, |
||||
|
app_id, |
||||
|
mch_id, |
||||
|
api_key, |
||||
|
apiclient_cert, |
||||
|
apiclient_key, |
||||
|
pub_key, |
||||
|
pub_key_id, |
||||
|
merchant_serial_number, |
||||
|
notify_url, |
||||
|
comments, |
||||
|
sort_number, |
||||
|
status, |
||||
|
deleted, |
||||
|
tenant_id, |
||||
|
create_time, |
||||
|
update_time |
||||
|
) VALUES ( |
||||
|
'微信支付-开发环境', |
||||
|
0, -- 微信支付 |
||||
|
'wechat_dev', |
||||
|
'/static/images/wechat_pay.png', |
||||
|
1, -- 普通商户 |
||||
|
'wx1234567890abcdef', -- 开发环境AppID |
||||
|
'1234567890', -- 开发环境商户号 |
||||
|
'your_dev_api_key_32_characters_long', |
||||
|
'dev/wechat/apiclient_cert.pem', |
||||
|
'dev/wechat/apiclient_key.pem', |
||||
|
'dev/wechat/wechatpay_cert.pem', |
||||
|
'your_pub_key_id', |
||||
|
'your_merchant_serial_number', |
||||
|
'http://frps-10550.s209.websoft.top/api/shop/shop-order/notify', -- 开发环境回调地址 |
||||
|
'开发环境专用配置,使用本地回调地址', |
||||
|
1, |
||||
|
1, -- 启用 |
||||
|
0, -- 未删除 |
||||
|
9999, -- 开发租户ID |
||||
|
NOW(), |
||||
|
NOW() |
||||
|
); |
||||
|
|
||||
|
-- 支付宝开发配置 |
||||
|
INSERT IGNORE INTO sys_payment ( |
||||
|
name, |
||||
|
type, |
||||
|
code, |
||||
|
app_id, |
||||
|
mch_id, |
||||
|
api_key, |
||||
|
notify_url, |
||||
|
comments, |
||||
|
sort_number, |
||||
|
status, |
||||
|
deleted, |
||||
|
tenant_id, |
||||
|
create_time, |
||||
|
update_time |
||||
|
) VALUES ( |
||||
|
'支付宝-开发环境', |
||||
|
1, -- 支付宝 |
||||
|
'alipay_dev', |
||||
|
'your_dev_alipay_app_id', |
||||
|
'your_dev_alipay_mch_id', |
||||
|
'your_dev_alipay_private_key', |
||||
|
'http://frps-10550.s209.websoft.top/api/shop/shop-order/notify', -- 开发环境回调地址 |
||||
|
'开发环境专用支付宝配置', |
||||
|
2, |
||||
|
1, -- 启用 |
||||
|
0, -- 未删除 |
||||
|
9999, -- 开发租户ID |
||||
|
NOW(), |
||||
|
NOW() |
||||
|
); |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 3. 创建开发环境用户(可选) |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 创建开发专用用户 |
||||
|
INSERT IGNORE INTO sys_user ( |
||||
|
user_id, |
||||
|
username, |
||||
|
password, |
||||
|
nickname, |
||||
|
avatar, |
||||
|
sex, |
||||
|
phone, |
||||
|
email, |
||||
|
email_verified, |
||||
|
real_name, |
||||
|
id_card, |
||||
|
birthday, |
||||
|
department_id, |
||||
|
status, |
||||
|
deleted, |
||||
|
tenant_id, |
||||
|
create_time, |
||||
|
update_time, |
||||
|
comments |
||||
|
) VALUES ( |
||||
|
99999, |
||||
|
'dev_user', |
||||
|
'$2a$10$yKTnKzKqKqKqKqKqKqKqKOKqKqKqKqKqKqKqKqKqKqKqKqKqKqKqK', -- 密码: dev123456 |
||||
|
'开发测试用户', |
||||
|
'/static/images/default_avatar.png', |
||||
|
1, |
||||
|
'13800000001', |
||||
|
'dev_user@websoft.top', |
||||
|
1, |
||||
|
'开发者', |
||||
|
'000000000000000000', |
||||
|
'1990-01-01', |
||||
|
1, |
||||
|
0, -- 正常状态 |
||||
|
0, -- 未删除 |
||||
|
9999, -- 开发租户ID |
||||
|
NOW(), |
||||
|
NOW(), |
||||
|
'开发环境专用测试用户' |
||||
|
); |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 4. 验证创建结果 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 检查租户创建结果 |
||||
|
SELECT |
||||
|
'Tenant Check' as check_type, |
||||
|
tenant_id, |
||||
|
tenant_name, |
||||
|
tenant_code, |
||||
|
status |
||||
|
FROM sys_tenant |
||||
|
WHERE tenant_id = 9999; |
||||
|
|
||||
|
-- 检查支付配置创建结果 |
||||
|
SELECT |
||||
|
'Payment Config Check' as check_type, |
||||
|
id, |
||||
|
name, |
||||
|
type, |
||||
|
notify_url, |
||||
|
tenant_id, |
||||
|
status |
||||
|
FROM sys_payment |
||||
|
WHERE tenant_id = 9999; |
||||
|
|
||||
|
-- 检查用户创建结果 |
||||
|
SELECT |
||||
|
'User Check' as check_type, |
||||
|
user_id, |
||||
|
username, |
||||
|
nickname, |
||||
|
tenant_id, |
||||
|
status |
||||
|
FROM sys_user |
||||
|
WHERE tenant_id = 9999; |
||||
|
|
||||
|
SELECT '开发环境配置创建完成!' as result; |
@ -0,0 +1,101 @@ |
|||||
|
-- 修复优惠券适用商品表字段缺失问题 |
||||
|
-- 作者: WebSoft |
||||
|
-- 日期: 2025-01-15 |
||||
|
-- 说明: 添加缺失的 goods_id 和 category_id 字段 |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 1. 检查表是否存在 |
||||
|
-- ======================================== |
||||
|
SELECT 'Checking table existence...' as status; |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 2. 添加缺失的字段 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 添加 goods_id 字段(如果不存在) |
||||
|
SET @sql = (SELECT IF( |
||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS |
||||
|
WHERE TABLE_SCHEMA = DATABASE() |
||||
|
AND TABLE_NAME = 'shop_coupon_apply_item' |
||||
|
AND COLUMN_NAME = 'goods_id') = 0, |
||||
|
'ALTER TABLE shop_coupon_apply_item ADD COLUMN goods_id INT(11) NULL COMMENT "商品ID" AFTER coupon_id;', |
||||
|
'SELECT "goods_id column already exists" as result;' |
||||
|
)); |
||||
|
PREPARE stmt FROM @sql; |
||||
|
EXECUTE stmt; |
||||
|
DEALLOCATE PREPARE stmt; |
||||
|
|
||||
|
-- 添加 category_id 字段(如果不存在) |
||||
|
SET @sql = (SELECT IF( |
||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS |
||||
|
WHERE TABLE_SCHEMA = DATABASE() |
||||
|
AND TABLE_NAME = 'shop_coupon_apply_item' |
||||
|
AND COLUMN_NAME = 'category_id') = 0, |
||||
|
'ALTER TABLE shop_coupon_apply_item ADD COLUMN category_id INT(11) NULL COMMENT "分类ID" AFTER goods_id;', |
||||
|
'SELECT "category_id column already exists" as result;' |
||||
|
)); |
||||
|
PREPARE stmt FROM @sql; |
||||
|
EXECUTE stmt; |
||||
|
DEALLOCATE PREPARE stmt; |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 3. 更新现有数据(如果需要) |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 如果表中有数据但 goods_id 为空,可以根据业务逻辑设置默认值 |
||||
|
-- 这里只是示例,实际需要根据业务需求调整 |
||||
|
UPDATE shop_coupon_apply_item |
||||
|
SET goods_id = pk |
||||
|
WHERE goods_id IS NULL AND type = 1 AND pk IS NOT NULL; |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 4. 添加索引优化查询性能 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 添加 goods_id 索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_coupon_apply_item_goods ON shop_coupon_apply_item(coupon_id, goods_id); |
||||
|
|
||||
|
-- 添加 category_id 索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_coupon_apply_item_category ON shop_coupon_apply_item(coupon_id, category_id); |
||||
|
|
||||
|
-- 添加类型索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_coupon_apply_item_type ON shop_coupon_apply_item(coupon_id, type); |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 5. 验证修复结果 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 检查表结构 |
||||
|
SELECT |
||||
|
COLUMN_NAME, |
||||
|
DATA_TYPE, |
||||
|
IS_NULLABLE, |
||||
|
COLUMN_DEFAULT, |
||||
|
COLUMN_COMMENT |
||||
|
FROM INFORMATION_SCHEMA.COLUMNS |
||||
|
WHERE TABLE_SCHEMA = DATABASE() |
||||
|
AND TABLE_NAME = 'shop_coupon_apply_item' |
||||
|
ORDER BY ORDINAL_POSITION; |
||||
|
|
||||
|
-- 检查数据 |
||||
|
SELECT |
||||
|
'Data check' as check_type, |
||||
|
COUNT(*) as total_records, |
||||
|
COUNT(goods_id) as records_with_goods_id, |
||||
|
COUNT(category_id) as records_with_category_id |
||||
|
FROM shop_coupon_apply_item; |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 6. 创建示例数据(可选) |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 如果表为空,插入一些示例数据用于测试 |
||||
|
INSERT IGNORE INTO shop_coupon_apply_item |
||||
|
(coupon_id, goods_id, category_id, type, status, tenant_id, create_time, update_time) |
||||
|
VALUES |
||||
|
(1, 1, NULL, 1, 0, 1, NOW(), NOW()), |
||||
|
(1, 2, NULL, 1, 0, 1, NOW(), NOW()), |
||||
|
(2, NULL, 1, 2, 0, 1, NOW(), NOW()), |
||||
|
(2, NULL, 2, 2, 0, 1, NOW(), NOW()); |
||||
|
|
||||
|
SELECT 'Database fix completed successfully!' as result; |
@ -0,0 +1,183 @@ |
|||||
|
-- 生产环境安全的支付配置脚本 |
||||
|
-- 此脚本可以安全地在生产数据库执行 |
||||
|
-- 不会创建测试数据,只添加必要的配置支持 |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 1. 检查当前环境(手动确认) |
||||
|
-- ======================================== |
||||
|
SELECT |
||||
|
'请确认这是您要修改的数据库' as warning, |
||||
|
DATABASE() as current_database, |
||||
|
NOW() as execution_time; |
||||
|
|
||||
|
-- 暂停执行,让用户确认 |
||||
|
-- 如果确认无误,请删除下面这行注释继续执行 |
||||
|
-- SELECT 'Please confirm this is the correct database before proceeding' as confirmation_required; |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 2. 添加支付配置表字段(如果不存在) |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 检查是否需要添加环境标识字段 |
||||
|
SELECT |
||||
|
CASE |
||||
|
WHEN COUNT(*) = 0 THEN '需要添加environment字段' |
||||
|
ELSE '环境字段已存在' |
||||
|
END as environment_field_status |
||||
|
FROM INFORMATION_SCHEMA.COLUMNS |
||||
|
WHERE TABLE_SCHEMA = DATABASE() |
||||
|
AND TABLE_NAME = 'sys_payment' |
||||
|
AND COLUMN_NAME = 'environment'; |
||||
|
|
||||
|
-- 添加环境标识字段(如果不存在) |
||||
|
SET @sql = (SELECT IF( |
||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS |
||||
|
WHERE TABLE_SCHEMA = DATABASE() |
||||
|
AND TABLE_NAME = 'sys_payment' |
||||
|
AND COLUMN_NAME = 'environment') = 0, |
||||
|
'ALTER TABLE sys_payment ADD COLUMN environment VARCHAR(20) DEFAULT "prod" COMMENT "环境标识(dev/test/prod)" AFTER tenant_id;', |
||||
|
'SELECT "environment column already exists" as result;' |
||||
|
)); |
||||
|
PREPARE stmt FROM @sql; |
||||
|
EXECUTE stmt; |
||||
|
DEALLOCATE PREPARE stmt; |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 3. 为现有支付配置添加环境标识 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 将现有配置标记为生产环境 |
||||
|
UPDATE sys_payment |
||||
|
SET environment = 'prod' |
||||
|
WHERE environment IS NULL OR environment = ''; |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 4. 创建开发环境配置的安全方式 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 方式1:复制现有生产配置作为开发模板(推荐) |
||||
|
-- 注意:这里使用您现有的租户ID,不创建新租户 |
||||
|
|
||||
|
-- 获取当前生产环境的微信支付配置 |
||||
|
SELECT |
||||
|
'当前微信支付配置' as config_type, |
||||
|
id, |
||||
|
name, |
||||
|
app_id, |
||||
|
mch_id, |
||||
|
notify_url, |
||||
|
tenant_id, |
||||
|
environment |
||||
|
FROM sys_payment |
||||
|
WHERE type = 0 AND status = 1 AND deleted = 0 |
||||
|
ORDER BY id DESC LIMIT 1; |
||||
|
|
||||
|
-- 获取当前生产环境的支付宝配置 |
||||
|
SELECT |
||||
|
'当前支付宝配置' as config_type, |
||||
|
id, |
||||
|
name, |
||||
|
app_id, |
||||
|
mch_id, |
||||
|
notify_url, |
||||
|
tenant_id, |
||||
|
environment |
||||
|
FROM sys_payment |
||||
|
WHERE type = 1 AND status = 1 AND deleted = 0 |
||||
|
ORDER BY id DESC LIMIT 1; |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 5. 手动创建开发配置的SQL模板 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 以下SQL需要您手动修改参数后执行 |
||||
|
-- 请根据上面查询的结果,修改相应的参数 |
||||
|
|
||||
|
/* |
||||
|
-- 微信支付开发配置模板(请修改参数后执行) |
||||
|
INSERT INTO sys_payment ( |
||||
|
name, type, code, image, wechat_type, |
||||
|
app_id, mch_id, api_key, apiclient_cert, apiclient_key, |
||||
|
pub_key, pub_key_id, merchant_serial_number, notify_url, |
||||
|
comments, sort_number, status, deleted, tenant_id, environment, |
||||
|
create_time, update_time |
||||
|
) VALUES ( |
||||
|
'微信支付-开发环境', |
||||
|
0, -- 微信支付 |
||||
|
'wechat_dev', |
||||
|
'/static/images/wechat_pay.png', |
||||
|
1, -- 普通商户 |
||||
|
'YOUR_DEV_APP_ID', -- 请替换为您的开发环境AppID |
||||
|
'YOUR_DEV_MCH_ID', -- 请替换为您的开发环境商户号 |
||||
|
'YOUR_DEV_API_KEY', -- 请替换为您的开发环境API密钥 |
||||
|
'dev/wechat/apiclient_cert.pem', |
||||
|
'dev/wechat/apiclient_key.pem', |
||||
|
'dev/wechat/wechatpay_cert.pem', |
||||
|
'YOUR_DEV_PUB_KEY_ID', |
||||
|
'YOUR_DEV_MERCHANT_SERIAL', |
||||
|
'http://frps-10550.s209.websoft.top/api/shop/shop-order/notify', -- 开发环境回调 |
||||
|
'开发环境专用配置', |
||||
|
1, |
||||
|
1, -- 启用 |
||||
|
0, -- 未删除 |
||||
|
YOUR_TENANT_ID, -- 请替换为您的租户ID |
||||
|
'dev', -- 开发环境标识 |
||||
|
NOW(), |
||||
|
NOW() |
||||
|
); |
||||
|
*/ |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 6. 更安全的方案:仅更新现有配置的回调地址 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 查看当前回调地址 |
||||
|
SELECT |
||||
|
'当前回调地址检查' as check_type, |
||||
|
id, |
||||
|
name, |
||||
|
type, |
||||
|
notify_url, |
||||
|
tenant_id, |
||||
|
environment |
||||
|
FROM sys_payment |
||||
|
WHERE status = 1 AND deleted = 0; |
||||
|
|
||||
|
-- 如果您只是想临时修改回调地址进行调试,可以使用以下SQL: |
||||
|
-- 注意:请先备份原始配置! |
||||
|
|
||||
|
/* |
||||
|
-- 备份当前配置 |
||||
|
CREATE TABLE IF NOT EXISTS sys_payment_backup AS |
||||
|
SELECT *, NOW() as backup_time FROM sys_payment WHERE status = 1; |
||||
|
|
||||
|
-- 临时修改回调地址(请谨慎使用) |
||||
|
UPDATE sys_payment |
||||
|
SET notify_url = 'http://frps-10550.s209.websoft.top/api/shop/shop-order/notify' |
||||
|
WHERE type = 0 AND tenant_id = YOUR_TENANT_ID AND status = 1; |
||||
|
|
||||
|
-- 恢复原始配置的SQL(调试完成后执行) |
||||
|
UPDATE sys_payment |
||||
|
SET notify_url = 'https://cms-api.websoft.top/api/shop/shop-order/notify' |
||||
|
WHERE type = 0 AND tenant_id = YOUR_TENANT_ID AND status = 1; |
||||
|
*/ |
||||
|
|
||||
|
-- ======================================== |
||||
|
-- 7. 验证配置 |
||||
|
-- ======================================== |
||||
|
|
||||
|
-- 检查所有支付配置 |
||||
|
SELECT |
||||
|
'最终配置检查' as check_type, |
||||
|
id, |
||||
|
name, |
||||
|
type, |
||||
|
notify_url, |
||||
|
tenant_id, |
||||
|
environment, |
||||
|
status |
||||
|
FROM sys_payment |
||||
|
WHERE deleted = 0 |
||||
|
ORDER BY tenant_id, type; |
||||
|
|
||||
|
SELECT '生产环境安全配置完成!请根据注释中的模板手动创建开发配置。' as result; |
@ -0,0 +1,17 @@ |
|||||
|
-- 简单修复优惠券适用商品表字段缺失问题 |
||||
|
-- 执行前请备份数据库 |
||||
|
|
||||
|
-- 1. 添加缺失的字段 |
||||
|
ALTER TABLE shop_coupon_apply_item |
||||
|
ADD COLUMN IF NOT EXISTS goods_id INT(11) NULL COMMENT '商品ID' AFTER coupon_id; |
||||
|
|
||||
|
ALTER TABLE shop_coupon_apply_item |
||||
|
ADD COLUMN IF NOT EXISTS category_id INT(11) NULL COMMENT '分类ID' AFTER goods_id; |
||||
|
|
||||
|
-- 2. 添加索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_coupon_apply_item_goods ON shop_coupon_apply_item(coupon_id, goods_id); |
||||
|
CREATE INDEX IF NOT EXISTS idx_coupon_apply_item_category ON shop_coupon_apply_item(coupon_id, category_id); |
||||
|
CREATE INDEX IF NOT EXISTS idx_coupon_apply_item_type ON shop_coupon_apply_item(coupon_id, type); |
||||
|
|
||||
|
-- 3. 检查表结构 |
||||
|
DESCRIBE shop_coupon_apply_item; |
Loading…
Reference in new issue