514 lines
12 KiB
Markdown
514 lines
12 KiB
Markdown
|
|
# Basic Config - 基础配置管理模块文档
|
|||
|
|
|
|||
|
|
## 模块概述
|
|||
|
|
|
|||
|
|
`basic_config` 是 OneApp 基础工具模块群中的配置管理模块,提供了应用配置的统一管理、API服务管控、版本控制等功能。该模块采用领域驱动设计(DDD)架构,支持动态配置更新、服务白名单管理和API访问控制。
|
|||
|
|
|
|||
|
|
### 基本信息
|
|||
|
|
- **模块名称**: basic_config
|
|||
|
|
- **模块路径**: oneapp_basic_utils/basic_config
|
|||
|
|
- **类型**: Flutter Package Module
|
|||
|
|
- **架构模式**: DDD (Domain Driven Design)
|
|||
|
|
- **主要功能**: 配置管理、API服务管控、版本管理
|
|||
|
|
|
|||
|
|
### 核心特性
|
|||
|
|
- **API服务管控**: 基于正则表达式的API路径匹配和访问控制
|
|||
|
|
- **服务白名单**: 支持白名单机制,允许特定服务绕过管控
|
|||
|
|
- **动态配置更新**: 支持运行时更新服务规则列表
|
|||
|
|
- **版本管理**: 内置版本比较和管理功能
|
|||
|
|
- **缓存优化**: 使用LRU缓存提升查询性能
|
|||
|
|
- **项目隔离**: 支持多项目代码隔离的配置管理
|
|||
|
|
|
|||
|
|
## 目录结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
basic_config/
|
|||
|
|
├── lib/
|
|||
|
|
│ ├── basic_config.dart # 模块入口文件
|
|||
|
|
│ └── src/
|
|||
|
|
│ ├── constants/ # 常量定义
|
|||
|
|
│ │ └── module_constant.dart
|
|||
|
|
│ ├── dependency/ # 依赖注入
|
|||
|
|
│ │ └── i_config_deps.dart
|
|||
|
|
│ ├── domains/ # 领域层
|
|||
|
|
│ │ ├── basic_config_facade.dart # 配置门面服务
|
|||
|
|
│ │ ├── entities/ # 实体对象
|
|||
|
|
│ │ │ ├── config_service_failures.dart
|
|||
|
|
│ │ │ ├── config_versions.dart
|
|||
|
|
│ │ │ └── project_services.dart
|
|||
|
|
│ │ ├── interfaces/ # 接口定义
|
|||
|
|
│ │ │ └── app_api_services_interface.dart
|
|||
|
|
│ │ └── value_objects/ # 值对象
|
|||
|
|
│ │ └── project_code.dart
|
|||
|
|
│ └── infrastructure/ # 基础设施层
|
|||
|
|
│ └── repositories/
|
|||
|
|
│ └── app_api_seervices_repository.dart
|
|||
|
|
└── pubspec.yaml # 依赖配置
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 核心架构组件
|
|||
|
|
|
|||
|
|
### 1. 版本管理 (Version)
|
|||
|
|
|
|||
|
|
提供语义化版本号的解析和比较功能:
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
mixin Version {
|
|||
|
|
/// 转成字符串格式
|
|||
|
|
String get toStr => '$major.$minor.$revision';
|
|||
|
|
|
|||
|
|
/// 版本比较 - 大于
|
|||
|
|
bool greaterThan(Version other) {
|
|||
|
|
if (major > other.major) return true;
|
|||
|
|
if (minor > other.minor && major == other.major) return true;
|
|||
|
|
if (revision > other.revision &&
|
|||
|
|
major == other.major &&
|
|||
|
|
minor == other.minor) return true;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 主版本号
|
|||
|
|
int get major;
|
|||
|
|
/// 次版本号
|
|||
|
|
int get minor;
|
|||
|
|
/// 修订版本号
|
|||
|
|
int get revision;
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
String toString() => toStr;
|
|||
|
|
|
|||
|
|
/// 解析版本字符串 (格式: x.x.x)
|
|||
|
|
static Version parseFrom(String versionStr) {
|
|||
|
|
final split = versionStr.split('.');
|
|||
|
|
if (split.length != 3) {
|
|||
|
|
throw UnsupportedError('parse version From $versionStr failed');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
final int major = int.parse(split[0]);
|
|||
|
|
final int minor = int.parse(split[1]);
|
|||
|
|
final int revision = int.parse(split[2]);
|
|||
|
|
|
|||
|
|
return _VersionImpl(major, minor, revision);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 项目服务实体 (ProjectServicesDo)
|
|||
|
|
|
|||
|
|
定义单个项目的服务配置信息:
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
class ProjectServicesDo {
|
|||
|
|
/// 构造函数
|
|||
|
|
/// [projectCode] 项目编号
|
|||
|
|
/// [ruleList] api path 正则规则
|
|||
|
|
/// [disableServiceList] 下架的服务列表
|
|||
|
|
ProjectServicesDo({
|
|||
|
|
required this.projectCode,
|
|||
|
|
required this.ruleList,
|
|||
|
|
required this.disableServiceList,
|
|||
|
|
}) : _ruleListRegex = ruleList.map(RegExp.new).toList(growable: false);
|
|||
|
|
|
|||
|
|
/// 项目编号
|
|||
|
|
final ProjectCodeVo projectCode;
|
|||
|
|
|
|||
|
|
/// 该项目对应的规则列表
|
|||
|
|
final List<String> ruleList;
|
|||
|
|
|
|||
|
|
/// 对应正则表达式
|
|||
|
|
final List<RegExp> _ruleListRegex;
|
|||
|
|
|
|||
|
|
/// 下架的服务
|
|||
|
|
final List<String> disableServiceList;
|
|||
|
|
|
|||
|
|
/// 检查路径是否匹配规则
|
|||
|
|
bool isMatchBy(String s) {
|
|||
|
|
bool match = false;
|
|||
|
|
for (final rule in _ruleListRegex) {
|
|||
|
|
match = rule.hasMatch(s);
|
|||
|
|
if (match) break;
|
|||
|
|
}
|
|||
|
|
return match;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 应用项目管理 (AppProjectsDo)
|
|||
|
|
|
|||
|
|
管理所有项目的服务配置:
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
class AppProjectsDo {
|
|||
|
|
/// 构造函数
|
|||
|
|
AppProjectsDo(this.version, this.projects) {
|
|||
|
|
for (final project in projects) {
|
|||
|
|
_projectsMap[project.projectCode.id] = project;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 版本号
|
|||
|
|
final int version;
|
|||
|
|
|
|||
|
|
/// app所有项目的信息
|
|||
|
|
List<ProjectServicesDo> projects;
|
|||
|
|
|
|||
|
|
/// 项目映射表
|
|||
|
|
final Map<String, ProjectServicesDo> _projectsMap = {};
|
|||
|
|
|
|||
|
|
/// 根据项目代码查找项目
|
|||
|
|
ProjectServicesDo? findBy(String projectCode) => _projectsMap[projectCode];
|
|||
|
|
|
|||
|
|
/// 检查服务是否已下架
|
|||
|
|
bool isServiceDisabled({
|
|||
|
|
required String projectCode,
|
|||
|
|
required String service,
|
|||
|
|
}) {
|
|||
|
|
try {
|
|||
|
|
final project = _projectsMap[projectCode];
|
|||
|
|
project!.disableServiceList.firstWhere((e) => e == service);
|
|||
|
|
return true;
|
|||
|
|
} catch (e) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 获取所有项目编号
|
|||
|
|
List<String> getProjectCodes() => _projectsMap.keys.toList(growable: false);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 基础配置门面 (BasicConfigFacade)
|
|||
|
|
|
|||
|
|
核心配置管理服务,采用单例模式:
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
abstract class IBasicConfigFacade {
|
|||
|
|
/// 初始化配置
|
|||
|
|
Future<Either<ConfigServiceFailures, Unit>> initialize({
|
|||
|
|
required String versionOfConnectivity,
|
|||
|
|
String jsonServiceList = '',
|
|||
|
|
List<String> whiteServiceList = const [],
|
|||
|
|
IBasicConfigDeps? deps,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/// 检查API是否命中管控规则
|
|||
|
|
Either<ConfigServiceFailures, bool> queryApiIfHit({
|
|||
|
|
String projectCode = '',
|
|||
|
|
String url = '',
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/// 检查API是否在白名单
|
|||
|
|
bool queryApiIfInWhiteList({required String url});
|
|||
|
|
|
|||
|
|
/// 主动更新服务规则列表
|
|||
|
|
Future<bool> updateServiceList({List<String> projectCodes = const []});
|
|||
|
|
|
|||
|
|
/// 检查服务是否下架
|
|||
|
|
bool isServiceDisabled({
|
|||
|
|
required String projectCode,
|
|||
|
|
required String service,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/// 根据项目代码查询项目信息
|
|||
|
|
Either<ConfigServiceFailures, ProjectServicesDo> queryProjectBy({
|
|||
|
|
String projectCode = '',
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/// 获取当前连接版本
|
|||
|
|
Version get currConnVersion;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 全局配置对象
|
|||
|
|
IBasicConfigFacade basicConfigFacade = BasicConfigFacadeImpl();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5. 具体实现 (BasicConfigFacadeImpl)
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
class BasicConfigFacadeImpl implements IBasicConfigFacade {
|
|||
|
|
BasicConfigFacadeImpl({IAppApiServiceRepo? appApiServiceRepo})
|
|||
|
|
: _apiServiceRepo = appApiServiceRepo ?? ApiServiceListRepository();
|
|||
|
|
|
|||
|
|
static const String _tag = 'BasicConfigFacadeImpl';
|
|||
|
|
|
|||
|
|
final IAppApiServiceRepo _apiServiceRepo;
|
|||
|
|
IBasicConfigDeps _deps = const DefaultConfigDeps();
|
|||
|
|
final _cache = LruCache<String, bool>(storage: InMemoryStorage(20));
|
|||
|
|
late Version _connVersion;
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Future<Either<ConfigServiceFailures, Unit>> initialize({
|
|||
|
|
required String versionOfConnectivity,
|
|||
|
|
String jsonServiceList = '',
|
|||
|
|
List<String> whiteServiceList = const [],
|
|||
|
|
IBasicConfigDeps? deps,
|
|||
|
|
}) async {
|
|||
|
|
if (deps != null) _deps = deps;
|
|||
|
|
_connVersion = Version.parseFrom(versionOfConnectivity);
|
|||
|
|
|
|||
|
|
// 初始化api管控配置列表
|
|||
|
|
final r = await _apiServiceRepo.initialize(
|
|||
|
|
deps: _deps,
|
|||
|
|
jsonServiceList: jsonServiceList,
|
|||
|
|
whiteServiceList: whiteServiceList,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
return r ? right(unit) : left(ConfigServiceFailures(
|
|||
|
|
errorCodeConfigServiceInvalidLocalServiceList,
|
|||
|
|
'initialize failed',
|
|||
|
|
));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Either<ConfigServiceFailures, bool> queryApiIfHit({
|
|||
|
|
String projectCode = '',
|
|||
|
|
String url = '',
|
|||
|
|
}) {
|
|||
|
|
final appProject = _apiServiceRepo.appProject;
|
|||
|
|
if (appProject == null) {
|
|||
|
|
return left(ConfigServiceFailures(
|
|||
|
|
errorCodeConfigServiceEmptyServiceList,
|
|||
|
|
'empty service list',
|
|||
|
|
));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
final findBy = appProject.findBy(projectCode);
|
|||
|
|
if (findBy == null) return right(false);
|
|||
|
|
|
|||
|
|
// 使用缓存优化查询性能
|
|||
|
|
final hitCache = _cache.get(url);
|
|||
|
|
if (hitCache == null) {
|
|||
|
|
final matchBy = findBy.isMatchBy(url);
|
|||
|
|
_cache.set(url, matchBy);
|
|||
|
|
return right(matchBy);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return right(hitCache);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 其他方法实现...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 使用指南
|
|||
|
|
|
|||
|
|
### 1. 初始化配置
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
import 'package:basic_config/basic_config.dart';
|
|||
|
|
|
|||
|
|
// 初始化基础配置
|
|||
|
|
await basicConfigFacade.initialize(
|
|||
|
|
versionOfConnectivity: '1.0.0',
|
|||
|
|
jsonServiceList: jsonConfigData,
|
|||
|
|
whiteServiceList: ['api/health', 'api/version'],
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. API访问控制
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
// 检查API是否命中管控规则
|
|||
|
|
final result = basicConfigFacade.queryApiIfHit(
|
|||
|
|
projectCode: 'oneapp_main',
|
|||
|
|
url: '/api/user/profile',
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
result.fold(
|
|||
|
|
(failure) => print('查询失败: ${failure.message}'),
|
|||
|
|
(isHit) => {
|
|||
|
|
if (isHit) {
|
|||
|
|
print('API被管控,需要特殊处理')
|
|||
|
|
} else {
|
|||
|
|
print('API正常访问')
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 白名单检查
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
// 检查API是否在白名单
|
|||
|
|
bool inWhiteList = basicConfigFacade.queryApiIfInWhiteList(
|
|||
|
|
url: '/api/health'
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if (inWhiteList) {
|
|||
|
|
// 白名单API,直接放行
|
|||
|
|
print('白名单API,允许访问');
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 服务状态检查
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
// 检查服务是否下架
|
|||
|
|
bool isDisabled = basicConfigFacade.isServiceDisabled(
|
|||
|
|
projectCode: 'oneapp_main',
|
|||
|
|
service: 'user_profile',
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if (isDisabled) {
|
|||
|
|
// 服务已下架,显示维护页面
|
|||
|
|
showMaintenancePage();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5. 动态更新配置
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
// 更新服务规则列表
|
|||
|
|
bool updateSuccess = await basicConfigFacade.updateServiceList(
|
|||
|
|
projectCodes: ['oneapp_main', 'oneapp_car'],
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if (updateSuccess) {
|
|||
|
|
print('配置更新成功');
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6. 版本管理
|
|||
|
|
|
|||
|
|
```dart
|
|||
|
|
// 版本解析和比较
|
|||
|
|
Version currentVersion = Version.parseFrom('1.2.3');
|
|||
|
|
Version newVersion = Version.parseFrom('1.2.4');
|
|||
|
|
|
|||
|
|
if (newVersion.greaterThan(currentVersion)) {
|
|||
|
|
print('发现新版本: ${newVersion.toStr}');
|
|||
|
|
// 执行更新逻辑
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 配置文件格式
|
|||
|
|
|
|||
|
|
### 服务配置JSON格式
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"version": 1,
|
|||
|
|
"projects": [
|
|||
|
|
{
|
|||
|
|
"projectCode": "oneapp_main",
|
|||
|
|
"ruleList": [
|
|||
|
|
"^/api/user/.*",
|
|||
|
|
"^/api/payment/.*"
|
|||
|
|
],
|
|||
|
|
"disableServiceList": [
|
|||
|
|
"old_payment_service",
|
|||
|
|
"deprecated_user_api"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"projectCode": "oneapp_car",
|
|||
|
|
"ruleList": [
|
|||
|
|
"^/api/vehicle/.*",
|
|||
|
|
"^/api/charging/.*"
|
|||
|
|
],
|
|||
|
|
"disableServiceList": []
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 依赖配置
|
|||
|
|
|
|||
|
|
### pubspec.yaml 关键依赖
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
dependencies:
|
|||
|
|
flutter:
|
|||
|
|
sdk: flutter
|
|||
|
|
|
|||
|
|
# 函数式编程支持
|
|||
|
|
dartz: ^0.10.1
|
|||
|
|
|
|||
|
|
# 基础日志模块
|
|||
|
|
basic_logger:
|
|||
|
|
path: ../basic_logger
|
|||
|
|
|
|||
|
|
# 基础存储模块
|
|||
|
|
basic_storage:
|
|||
|
|
path: ../basic_storage
|
|||
|
|
|
|||
|
|
dev_dependencies:
|
|||
|
|
flutter_test:
|
|||
|
|
sdk: flutter
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 架构设计原则
|
|||
|
|
|
|||
|
|
### 1. DDD分层架构
|
|||
|
|
- **Domain层**: 包含业务实体、值对象和领域服务
|
|||
|
|
- **Infrastructure层**: 处理数据持久化和外部服务调用
|
|||
|
|
- **Application层**: 通过Facade模式提供应用服务
|
|||
|
|
|
|||
|
|
### 2. 函数式编程
|
|||
|
|
- 使用`dartz`包提供的`Either`类型处理错误
|
|||
|
|
- 避免异常抛出,通过类型系统表达可能的失败情况
|
|||
|
|
|
|||
|
|
### 3. 依赖注入
|
|||
|
|
- 通过接口定义依赖,支持测试替换
|
|||
|
|
- 使用抽象类定义服务边界
|
|||
|
|
|
|||
|
|
## 性能优化
|
|||
|
|
|
|||
|
|
### 1. 缓存策略
|
|||
|
|
- 使用LRU缓存存储API匹配结果
|
|||
|
|
- 缓存大小限制为20个条目,避免内存过度使用
|
|||
|
|
|
|||
|
|
### 2. 正则表达式优化
|
|||
|
|
- 预编译正则表达式,避免重复编译开销
|
|||
|
|
- 使用不可变列表存储编译后的正则
|
|||
|
|
|
|||
|
|
### 3. 查询优化
|
|||
|
|
- 使用Map结构优化项目查找性能
|
|||
|
|
- 短路求值减少不必要的匹配操作
|
|||
|
|
|
|||
|
|
## 最佳实践
|
|||
|
|
|
|||
|
|
### 1. 错误处理
|
|||
|
|
```dart
|
|||
|
|
// 推荐:使用Either处理可能的错误
|
|||
|
|
final result = basicConfigFacade.queryApiIfHit(
|
|||
|
|
projectCode: projectCode,
|
|||
|
|
url: url,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
result.fold(
|
|||
|
|
(failure) => handleFailure(failure),
|
|||
|
|
(success) => handleSuccess(success),
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 不推荐:使用try-catch
|
|||
|
|
try {
|
|||
|
|
final result = riskyOperation();
|
|||
|
|
handleSuccess(result);
|
|||
|
|
} catch (e) {
|
|||
|
|
handleError(e);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 配置管理
|
|||
|
|
- 在应用启动时初始化配置
|
|||
|
|
- 定期检查和更新远程配置
|
|||
|
|
- 为关键服务提供降级策略
|
|||
|
|
|
|||
|
|
### 3. 测试策略
|
|||
|
|
- 使用依赖注入进行单元测试
|
|||
|
|
- 模拟网络请求测试异常情况
|
|||
|
|
- 验证缓存行为的正确性
|
|||
|
|
|
|||
|
|
## 问题排查
|
|||
|
|
|
|||
|
|
### 常见问题
|
|||
|
|
1. **初始化失败**: 检查配置JSON格式和依赖注入设置
|
|||
|
|
2. **正则匹配异常**: 验证规则列表中的正则表达式语法
|
|||
|
|
3. **缓存不生效**: 确认URL格式一致性
|
|||
|
|
|
|||
|
|
### 调试技巧
|
|||
|
|
- 启用详细日志查看配置加载过程
|
|||
|
|
- 使用`basicConfigTag`过滤相关日志
|
|||
|
|
- 检查版本解析是否符合x.x.x格式
|