配置管理.md 18 KB

文件模块存储配置管理

1. 概述

文件模块存储配置管理功能旨在将文件系统配置(特别是存储磁盘配置)从config/filesystems.php文件中迁移到数据库中存储,提供更灵活、更易于管理的配置方式。通过数据库存储配置,可以实现存储磁盘的动态调整、版本管理和权限控制,无需修改代码或重启应用即可更新配置。

这种方式特别适合需要频繁调整存储配置的场景,例如:

  • 在不同环境(开发、测试、生产)之间切换存储方式
  • 动态添加或移除云存储提供商
  • 根据业务需求调整存储策略
  • 实现存储服务的灰度发布或A/B测试

2. 设计目标

  • 集中管理:将文件系统存储配置集中存储在数据库中,便于统一管理
  • 动态更新:支持在运行时动态更新存储配置,无需修改代码或重启应用
  • 版本控制:记录存储配置的变更历史,支持配置回滚,便于问题排查
  • 权限管理:基于角色的存储配置访问和修改权限,避免未授权的配置变更
  • 默认值:提供合理的默认存储配置,确保系统在无配置时仍能正常运行
  • 缓存机制:优化存储配置读取性能,减少数据库访问,提高系统响应速度
  • 多环境支持:支持不同环境(开发、测试、生产)使用不同的存储配置
  • 可视化管理:提供直观的后台界面,便于管理员配置和管理存储服务

3. 数据库设计

-- 存储配置表
CREATE TABLE `file_storage_configs` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(100) NOT NULL COMMENT '存储磁盘名称,唯一',
  `driver` varchar(50) NOT NULL COMMENT '存储驱动(local, s3, oss等)',
  `config` text NOT NULL COMMENT '配置值,JSON格式',
  `description` varchar(500) DEFAULT '' COMMENT '配置描述',
  `is_default` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否默认存储,1表示是,0表示否',
  `is_temp` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否用于临时存储,1表示是,0表示否',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:1-启用,0-禁用',
  `env` varchar(50) NOT NULL DEFAULT 'production' COMMENT '环境(development, testing, production)',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `created_by` int(11) NOT NULL DEFAULT '0' COMMENT '创建人ID',
  `updated_by` int(11) NOT NULL DEFAULT '0' COMMENT '更新人ID',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_name_env` (`name`,`env`),
  KEY `idx_status` (`status`),
  KEY `idx_env` (`env`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件存储配置表';

-- 存储配置历史表
CREATE TABLE `file_storage_config_histories` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `config_id` bigint(20) NOT NULL COMMENT '关联的存储配置ID',
  `old_driver` varchar(50) DEFAULT NULL COMMENT '旧存储驱动',
  `new_driver` varchar(50) DEFAULT NULL COMMENT '新存储驱动',
  `old_config` text DEFAULT NULL COMMENT '旧配置值',
  `new_config` text DEFAULT NULL COMMENT '新配置值',
  `old_status` tinyint(1) DEFAULT NULL COMMENT '旧状态',
  `new_status` tinyint(1) DEFAULT NULL COMMENT '新状态',
  `changed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '变更时间',
  `changed_by` int(11) NOT NULL DEFAULT '0' COMMENT '变更人ID',
  `change_reason` varchar(500) DEFAULT '' COMMENT '变更原因',
  PRIMARY KEY (`id`),
  KEY `idx_config_id` (`config_id`),
  KEY `idx_changed_at` (`changed_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件存储配置变更历史表';

3.1 存储配置表 (file_storage_configs)

字段名 类型 说明
id bigint 主键
name varchar(100) 存储磁盘名称,唯一
driver varchar(50) 存储驱动(local, s3, oss等)
config text 配置值,JSON格式
description varchar(500) 配置描述
is_default tinyint 是否默认存储,1表示是,0表示否
is_temp tinyint 是否用于临时存储,1表示是,0表示否
status tinyint 状态:1-启用,0-禁用
env varchar(50) 环境(development, testing, production)
created_at timestamp 创建时间
updated_at timestamp 更新时间
created_by int 创建人ID
updated_by int 更新人ID

3.2 存储配置历史表 (file_storage_config_histories)

字段名 类型 说明
id bigint 主键
config_id bigint 关联的存储配置ID
old_driver varchar(50) 旧存储驱动
new_driver varchar(50) 新存储驱动
old_config text 旧配置值
new_config text 新配置值
old_status tinyint 旧状态
new_status tinyint 新状态
changed_at timestamp 变更时间
changed_by int 变更人ID
change_reason varchar(500) 变更原因

4. 存储驱动配置示例

以下是不同存储驱动的配置示例,这些配置将以JSON格式存储在config字段中:

4.1 本地存储 (local)

{
  "driver": "local",
  "root": "/path/to/storage",
  "url": "http://example.com/storage",
  "visibility": "public",
  "throw": true
}

4.2 阿里云对象存储 (oss)

{
  "driver": "oss",
  "access_key_id": "your-access-key-id",
  "access_key_secret": "your-access-key-secret",
  "bucket": "your-bucket-name",
  "endpoint": "oss-cn-hangzhou.aliyuncs.com",
  "url": "https://your-bucket-name.oss-cn-hangzhou.aliyuncs.com",
  "internal": false,
  "throw": true
}

4.3 亚马逊S3 (s3)

{
  "driver": "s3",
  "key": "your-key",
  "secret": "your-secret",
  "region": "us-east-1",
  "bucket": "your-bucket-name",
  "url": "https://your-bucket-name.s3.amazonaws.com",
  "endpoint": null,
  "use_path_style_endpoint": false,
  "throw": true
}

4.4 腾讯云对象存储 (cos)

{
  "driver": "cos",
  "app_id": "your-app-id",
  "secret_id": "your-secret-id",
  "secret_key": "your-secret-key",
  "region": "ap-guangzhou",
  "bucket": "your-bucket-name",
  "url": "https://your-bucket-name-your-app-id.cos.ap-guangzhou.myqcloud.com",
  "throw": true
}

4.5 七牛云存储 (qiniu)

{
  "driver": "qiniu",
  "access_key": "your-access-key",
  "secret_key": "your-secret-key",
  "bucket": "your-bucket-name",
  "domain": "http://your-domain.com",
  "throw": true
}

5. 服务设计

5.1 StorageConfigService

存储配置服务负责存储配置的读取、更新和缓存管理。

class StorageConfigService
{
    /**
     * 获取默认存储磁盘配置
     *
     * @return FileStorageConfig|null 存储配置模型
     */
    public function getDefaultDisk();

    /**
     * 获取临时存储磁盘配置
     *
     * @return FileStorageConfig|null 存储配置模型
     */
    public function getTempDisk();

    /**
     * 获取指定名称的存储磁盘配置
     *
     * @param string $name 存储磁盘名称
     * @return FileStorageConfig|null 存储配置模型
     */
    public function getDisk(string $name);

    /**
     * 获取所有启用的存储磁盘配置
     *
     * @param string|null $env 环境名称,为null时获取所有环境
     * @return Collection 存储配置集合
     */
    public function getAllDisks(string $env = null);

    /**
     * 创建存储磁盘配置
     *
     * @param string $name 存储磁盘名称
     * @param string $driver 存储驱动
     * @param array $config 配置值
     * @param string $description 配置描述
     * @param bool $isDefault 是否默认存储
     * @param bool $isTemp 是否用于临时存储
     * @param string $env 环境名称
     * @param int $createdBy 创建人ID
     * @return FileStorageConfig 存储配置模型
     */
    public function createDisk(string $name, string $driver, array $config, string $description = '', bool $isDefault = false, bool $isTemp = false, string $env = 'production', int $createdBy = 0);

    /**
     * 更新存储磁盘配置
     *
     * @param int $id 存储配置ID
     * @param string $driver 存储驱动
     * @param array $config 配置值
     * @param string $description 配置描述
     * @param bool $isDefault 是否默认存储
     * @param bool $isTemp 是否用于临时存储
     * @param int $status 状态
     * @param int $updatedBy 更新人ID
     * @param string $reason 变更原因
     * @return FileStorageConfig 存储配置模型
     */
    public function updateDisk(int $id, string $driver, array $config, string $description = '', bool $isDefault = false, bool $isTemp = false, int $status = 1, int $updatedBy = 0, string $reason = '');

    /**
     * 删除存储磁盘配置
     *
     * @param int $id 存储配置ID
     * @param int $deletedBy 删除人ID
     * @param string $reason 删除原因
     * @return bool 是否成功
     */
    public function deleteDisk(int $id, int $deletedBy = 0, string $reason = '');

    /**
     * 设置默认存储磁盘
     *
     * @param int $id 存储配置ID
     * @param int $updatedBy 更新人ID
     * @return bool 是否成功
     */
    public function setDefaultDisk(int $id, int $updatedBy = 0);

    /**
     * 设置临时存储磁盘
     *
     * @param int $id 存储配置ID
     * @param int $updatedBy 更新人ID
     * @return bool 是否成功
     */
    public function setTempDisk(int $id, int $updatedBy = 0);

    /**
     * 获取存储磁盘配置变更历史
     *
     * @param int $configId 存储配置ID
     * @return Collection 配置历史集合
     */
    public function getHistory(int $configId);

    /**
     * 清除存储配置缓存
     *
     * @return void
     */
    public function clearCache();
}

5.2 StorageConfigRepository

存储配置仓库负责与数据库的交互。

class StorageConfigRepository
{
    /**
     * 获取默认存储磁盘配置
     *
     * @param string|null $env 环境名称
     * @return FileStorageConfig|null 存储配置模型
     */
    public function findDefault(string $env = null);

    /**
     * 获取临时存储磁盘配置
     *
     * @param string|null $env 环境名称
     * @return FileStorageConfig|null 存储配置模型
     */
    public function findTemp(string $env = null);

    /**
     * 获取指定名称的存储磁盘配置
     *
     * @param string $name 存储磁盘名称
     * @param string|null $env 环境名称
     * @return FileStorageConfig|null 存储配置模型
     */
    public function findByName(string $name, string $env = null);

    /**
     * 获取所有启用的存储磁盘配置
     *
     * @param string|null $env 环境名称
     * @return Collection 存储配置集合
     */
    public function findAllEnabled(string $env = null);

    /**
     * 创建存储磁盘配置
     *
     * @param array $data 配置数据
     * @return FileStorageConfig 存储配置模型
     */
    public function create(array $data);

    /**
     * 更新存储磁盘配置
     *
     * @param int $id 存储配置ID
     * @param array $data 配置数据
     * @return FileStorageConfig 存储配置模型
     */
    public function update(int $id, array $data);

    /**
     * 删除存储磁盘配置
     *
     * @param int $id 存储配置ID
     * @return bool 是否成功
     */
    public function delete(int $id);

    /**
     * 记录存储配置变更历史
     *
     * @param int $configId 存储配置ID
     * @param array $oldData 旧数据
     * @param array $newData 新数据
     * @param int $changedBy 变更人ID
     * @param string $reason 变更原因
     * @return FileStorageConfigHistory 配置历史模型
     */
    public function recordHistory(int $configId, array $oldData, array $newData, int $changedBy, string $reason);

    /**
     * 获取存储配置变更历史
     *
     * @param int $configId 存储配置ID
     * @return Collection 配置历史集合
     */
    public function getHistory(int $configId);
}

6. 使用示例

6.1 获取存储配置

// 获取存储配置服务
$storageConfigService = app(\App\Module\File\Services\StorageConfigService::class);

// 获取默认存储磁盘配置
$defaultDiskConfig = $storageConfigService->getDefaultDisk();
$defaultDiskName = $defaultDiskConfig ? $defaultDiskConfig->name : 'local';

// 获取临时存储磁盘配置
$tempDiskConfig = $storageConfigService->getTempDisk();
$tempDiskName = $tempDiskConfig ? $tempDiskConfig->name : $defaultDiskName;

// 获取指定名称的存储磁盘配置
$ossDiskConfig = $storageConfigService->getDisk('oss');

// 获取所有启用的存储磁盘配置
$allDisks = $storageConfigService->getAllDisks();

// 获取特定环境的存储磁盘配置
$productionDisks = $storageConfigService->getAllDisks('production');

6.2 创建和更新存储配置

// 获取存储配置服务
$storageConfigService = app(\App\Module\File\Services\StorageConfigService::class);

// 创建本地存储配置
$localConfig = [
    'driver' => 'local',
    'root' => storage_path('app/public'),
    'url' => env('APP_URL').'/storage',
    'visibility' => 'public',
    'throw' => true
];
$storageConfigService->createDisk('local', 'local', $localConfig, '本地公共存储', true, false, 'production', auth()->id());

// 创建阿里云OSS存储配置
$ossConfig = [
    'driver' => 'oss',
    'access_key_id' => 'your-access-key-id',
    'access_key_secret' => 'your-access-key-secret',
    'bucket' => 'your-bucket-name',
    'endpoint' => 'oss-cn-hangzhou.aliyuncs.com',
    'url' => 'https://your-bucket-name.oss-cn-hangzhou.aliyuncs.com',
    'internal' => false,
    'throw' => true
];
$storageConfigService->createDisk('oss', 'oss', $ossConfig, '阿里云OSS存储', false, false, 'production', auth()->id());

// 创建临时存储配置
$tempConfig = [
    'driver' => 'local',
    'root' => storage_path('app/temp'),
    'url' => env('APP_URL').'/temp',
    'visibility' => 'private',
    'throw' => true
];
$storageConfigService->createDisk('temp', 'local', $tempConfig, '临时文件存储', false, true, 'production', auth()->id());

// 更新存储配置
$updatedOssConfig = [
    'driver' => 'oss',
    'access_key_id' => 'new-access-key-id',
    'access_key_secret' => 'new-access-key-secret',
    'bucket' => 'new-bucket-name',
    'endpoint' => 'oss-cn-beijing.aliyuncs.com',
    'url' => 'https://new-bucket-name.oss-cn-beijing.aliyuncs.com',
    'internal' => false,
    'throw' => true
];
$storageConfigService->updateDisk(2, 'oss', $updatedOssConfig, '阿里云OSS存储(北京)', false, false, 1, auth()->id(), '更新为北京区域的OSS');

// 设置默认存储磁盘
$storageConfigService->setDefaultDisk(2, auth()->id());

// 设置临时存储磁盘
$storageConfigService->setTempDisk(3, auth()->id());

6.3 在TemporaryService中使用存储配置

/**
 * 获取临时文件存储磁盘
 *
 * @return \Illuminate\Contracts\Filesystem\Filesystem
 */
private function getDisk()
{
    // 获取存储配置服务
    $storageConfigService = app(\App\Module\File\Services\StorageConfigService::class);

    // 获取临时存储磁盘配置
    $tempDiskConfig = $storageConfigService->getTempDisk();

    // 如果没有配置临时存储磁盘,则使用默认存储磁盘
    if (!$tempDiskConfig) {
        $defaultDiskConfig = $storageConfigService->getDefaultDisk();
        $diskName = $defaultDiskConfig ? $defaultDiskConfig->name : 'local';
    } else {
        $diskName = $tempDiskConfig->name;
    }

    return Storage::disk($diskName);
}

6.4 获取存储配置历史

// 获取存储配置服务
$storageConfigService = app(\App\Module\File\Services\StorageConfigService::class);

// 获取存储配置历史
$configId = 2; // OSS配置ID
$history = $storageConfigService->getHistory($configId);

// 显示历史记录
foreach ($history as $record) {
    echo "变更时间: " . $record->changed_at . "\n";
    echo "变更人: " . $record->changed_by . "\n";
    echo "变更原因: " . $record->change_reason . "\n";
    echo "旧驱动: " . $record->old_driver . " -> 新驱动: " . $record->new_driver . "\n";
    echo "旧配置: " . json_encode($record->old_config) . "\n";
    echo "新配置: " . json_encode($record->new_config) . "\n";
    echo "-------------------\n";
}

7. 实施计划

7.1 第一阶段:基础设施

  1. 创建数据库表:file_storage_configs和file_storage_config_histories
  2. 实现FileStorageConfig和FileStorageConfigHistory模型
  3. 实现StorageConfigRepository和StorageConfigService
  4. 添加默认存储配置数据

7.2 第二阶段:集成现有功能

  1. 修改Storage类,使用存储配置服务获取存储配置
  2. 修改TemporaryService,使用存储配置服务获取临时存储配置
  3. 修改ImgService和UploadService,使用存储配置服务获取存储配置
  4. 添加配置缓存机制,优化性能

7.3 第三阶段:后台管理

  1. 实现存储配置管理后台界面
    • 存储磁盘列表
    • 创建/编辑存储磁盘表单
    • 设置默认/临时存储磁盘功能
    • 存储配置历史查看功能
  2. 实现存储配置测试功能
    • 测试存储连接是否正常
    • 测试上传和下载功能
  3. 实现存储配置导出和导入功能

7.4 第四阶段:优化和扩展

  1. 实现存储配置的环境隔离(开发、测试、生产)
  2. 添加存储配置变更通知机制
  3. 实现存储使用统计和监控功能
  4. 实现存储自动切换和故障转移功能

8. 注意事项

  1. 性能考虑

    • 存储配置读取是高频操作,应实现有效的缓存机制
    • 可以使用Laravel的缓存系统缓存存储配置
    • 配置变更时应自动清除缓存
  2. 兼容性

    • 确保现有代码在配置迁移过程中不受影响
    • 提供与现有代码兼容的接口
    • 考虑添加配置回退机制,当数据库配置不可用时使用配置文件
  3. 安全性

    • 存储配置中包含敏感信息(如密钥),应加密存储
    • 限制存储配置的访问和修改权限
    • 记录所有配置变更操作,便于审计
  4. 可用性

    • 所有存储配置都应有合理的默认值
    • 确保系统在无配置时仍能正常运行
    • 提供配置验证机制,避免错误配置导致系统不可用
  5. 文档和培训

    • 及时更新存储配置文档
    • 提供详细的使用示例
    • 对管理员进行培训,确保正确使用存储配置功能