feat(device): 添加默认配置管理功能

- 新增 DefaultConfigClient接口,用于与设备微服务进行默认配置相关的操作
- 实现 DefaultConfigIntegrationService 类,提供默认配置管理的高阶服务- 添加批量配置请求构建器 BatchDefaultConfigRequestBuilder,简化批量操作
- 新增 DefaultConfigIntegrationExample 示例类,演示默认配置管理的使用方法
- 更新 CLAUDE.md 文档,增加默认配置管理的详细使用说明和示例代码
This commit is contained in:
2025-09-05 14:49:06 +08:00
parent 933a1209e7
commit 933818d458
9 changed files with 1046 additions and 0 deletions

View File

@@ -227,10 +227,12 @@ fallbackService.clearAllFallbackCache("zt-scenic");
#### Feign Clients #### Feign Clients
- **DeviceV2Client**: Main device operations (CRUD, filtering, listing) - **DeviceV2Client**: Main device operations (CRUD, filtering, listing)
- **DeviceConfigV2Client**: Device configuration management - **DeviceConfigV2Client**: Device configuration management
- **DefaultConfigClient**: Default configuration management
#### Services #### Services
- **DeviceIntegrationService**: High-level device operations (with automatic fallback) - **DeviceIntegrationService**: High-level device operations (with automatic fallback)
- **DeviceConfigIntegrationService**: Device configuration management (with automatic fallback) - **DeviceConfigIntegrationService**: Device configuration management (with automatic fallback)
- **DefaultConfigIntegrationService**: Default configuration management (with automatic fallback)
#### Configuration #### Configuration
```yaml ```yaml
@@ -377,6 +379,355 @@ fallbackService.clearFallbackCache("zt-device", "device:1001");
fallbackService.clearAllFallbackCache("zt-device"); fallbackService.clearAllFallbackCache("zt-device");
``` ```
## Default Configuration Management (ZT-Device Microservice)
### Key Components
#### Default Configuration API
The zt-device microservice provides a comprehensive default configuration management API at `/api/device/config/v2/defaults` that allows:
- Creating and managing default configuration templates
- Batch operations with conflict detection
- Configuration type validation and enforcement
- Usage tracking and analytics
#### Feign Client
- **DefaultConfigClient**: Default configuration management operations
#### Service
- **DefaultConfigIntegrationService**: High-level default configuration operations (with automatic fallback for queries)
### Usage Examples
#### Basic Default Configuration Operations (with Automatic Fallback)
```java
@Autowired
private DefaultConfigIntegrationService defaultConfigService;
// Get default configuration list (automatically falls back to cache on failure)
PageResponse<DefaultConfigResponse> configList = defaultConfigService.listDefaultConfigs(1, 10);
log.info("Default configs: total={}, current page={}",
configList.getData().getTotal(), configList.getData().getList().size());
// Get specific default configuration (automatically falls back to cache on failure)
DefaultConfigResponse config = defaultConfigService.getDefaultConfig("resolution");
if (config != null) {
log.info("Default resolution: {}", config.getConfigValue());
}
// Create new default configuration (direct operation, fails immediately on error)
DefaultConfigRequest newConfig = new DefaultConfigRequest();
newConfig.setConfigKey("bitrate");
newConfig.setConfigValue("2000000");
newConfig.setConfigType("int");
newConfig.setDescription("Default video bitrate in bps");
boolean created = defaultConfigService.createDefaultConfig(newConfig);
// Update default configuration with conflict detection (direct operation)
Map<String, Object> updates = new HashMap<>();
updates.put("configValue", "4000000");
updates.put("description", "Updated default bitrate - high quality");
DefaultConfigConflict conflict = defaultConfigService.updateDefaultConfig("bitrate", updates);
if (conflict != null) {
log.warn("Configuration update conflict detected:");
log.warn(" Key: {}, Type: {}, Affected devices: {}",
conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
log.warn(" Current type: {}, Proposed type: {}",
conflict.getCurrentType(), conflict.getProposedType());
// Handle conflict - show affected device IDs
if (conflict.getConflictDevices() != null) {
log.warn(" Conflicted device IDs: {}", conflict.getConflictDevices());
}
} else {
log.info("Configuration updated successfully without conflicts");
}
// Delete default configuration (direct operation, fails immediately on error)
boolean deleted = defaultConfigService.deleteDefaultConfig("bitrate");
```
#### Batch Default Configuration Operations
```java
// Using Builder Pattern for batch operations
BatchDefaultConfigRequest batchRequest = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("1920x1080", 30, "H265") // Add video configuration group
.addNetworkConfig("192.168.1.100", 554, "RTSP") // Add network configuration group
.addConfig("recording_enabled", "true", "bool", "Enable recording by default")
.addConfig("storage_retention", "30", "int", "Storage retention in days")
.addConfig("quality_profile", "high", "string", "Default video quality profile")
.build();
// Execute batch update (direct operation, no fallback)
BatchDefaultConfigResponse result = defaultConfigService.batchUpdateDefaultConfigs(batchRequest);
// Process batch results
log.info("Batch operation completed: {} success, {} failed", result.getSuccess(), result.getFailed());
// Handle conflicts
if (result.getConflicts() != null && !result.getConflicts().isEmpty()) {
log.warn("Configuration conflicts detected:");
for (DefaultConfigConflict conflict : result.getConflicts()) {
log.warn(" Key: {}, Type: {}, Devices affected: {}",
conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
}
}
// Review processed items
if (result.getProcessedItems() != null) {
result.getProcessedItems().forEach(item -> {
if ("success".equals(item.getStatus())) {
log.info("✅ {} {} successfully (type: {})",
item.getConfigKey(), item.getAction(), item.getFinalType());
} else {
log.warn("❌ {} failed: {}", item.getConfigKey(), item.getMessage());
}
});
}
// Handle errors
if (result.getErrors() != null && !result.getErrors().isEmpty()) {
result.getErrors().forEach(error -> log.error("Batch operation error: {}", error));
}
```
#### Device Type Specific Default Configuration Patterns
```java
// Create IPC camera default configurations
BatchDefaultConfigRequest ipcDefaults = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("1920x1080", 25, "H264") // Standard HD resolution
.addConfig("night_vision", "true", "bool", "Enable night vision")
.addConfig("motion_detection", "true", "bool", "Enable motion detection")
.addConfig("stream_profile", "main", "string", "Default stream profile")
.addConfig("ptz_enabled", "false", "bool", "PTZ control enabled")
.addConfig("audio_enabled", "true", "bool", "Audio recording enabled")
.build();
// Create NVR default configurations
BatchDefaultConfigRequest nvrDefaults = defaultConfigService.createBatchConfigBuilder()
.addConfig("max_channels", "16", "int", "Maximum supported channels")
.addConfig("storage_mode", "continuous", "string", "Recording storage mode")
.addConfig("backup_enabled", "true", "bool", "Enable automatic backup")
.addConfig("raid_level", "5", "int", "Default RAID level")
.addConfig("disk_quota", "80", "int", "Disk usage quota percentage")
.build();
// Apply device-type-specific defaults
BatchDefaultConfigResponse ipcResult = defaultConfigService.batchUpdateDefaultConfigs(ipcDefaults);
BatchDefaultConfigResponse nvrResult = defaultConfigService.batchUpdateDefaultConfigs(nvrDefaults);
log.info("IPC defaults: {} success, {} failed", ipcResult.getSuccess(), ipcResult.getFailed());
log.info("NVR defaults: {} success, {} failed", nvrResult.getSuccess(), nvrResult.getFailed());
```
#### Configuration Validation and Management Patterns
```java
// Validate system configuration completeness
PageResponse<DefaultConfigResponse> allDefaults = defaultConfigService.listDefaultConfigs(1, 100);
// Check for required default configurations
String[] requiredDefaults = {
"resolution", "frameRate", "codec", "bitrate",
"protocol", "port", "username", "password"
};
Map<String, Boolean> configStatus = new HashMap<>();
for (String required : requiredDefaults) {
boolean exists = allDefaults.getData().getList().stream()
.anyMatch(config -> required.equals(config.getConfigKey()));
configStatus.put(required, exists);
if (!exists) {
log.warn("Missing required default configuration: {}", required);
}
}
// Generate configuration completeness report
long totalConfigs = allDefaults.getData().getTotal();
long completeConfigs = configStatus.values().stream().mapToLong(exists -> exists ? 1 : 0).sum();
double completeness = (double) completeConfigs / requiredDefaults.length * 100;
log.info("Configuration completeness: {:.1f}% ({}/{} required configs present)",
completeness, completeConfigs, requiredDefaults.length);
log.info("Total default configurations in system: {}", totalConfigs);
// Analyze configuration type distribution
Map<String, Long> typeDistribution = allDefaults.getData().getList().stream()
.collect(Collectors.groupingBy(
DefaultConfigResponse::getConfigType,
Collectors.counting()
));
log.info("Configuration type distribution: {}", typeDistribution);
// Find most and least used configurations
DefaultConfigResponse mostUsed = allDefaults.getData().getList().stream()
.max(Comparator.comparing(DefaultConfigResponse::getUsageCount))
.orElse(null);
DefaultConfigResponse leastUsed = allDefaults.getData().getList().stream()
.min(Comparator.comparing(DefaultConfigResponse::getUsageCount))
.orElse(null);
if (mostUsed != null) {
log.info("Most used default config: {} (used {} times)",
mostUsed.getConfigKey(), mostUsed.getUsageCount());
}
if (leastUsed != null) {
log.info("Least used default config: {} (used {} times)",
leastUsed.getConfigKey(), leastUsed.getUsageCount());
}
```
#### Advanced Batch Configuration with Error Handling
```java
// Complex batch operation with comprehensive error handling
try {
BatchDefaultConfigRequest complexBatch = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("3840x2160", 60, "H265") // 4K configuration
.addConfig("hdr_enabled", "true", "bool", "HDR video support")
.addConfig("ai_analysis", "enabled", "string", "AI analysis features")
.addConfig("edge_processing", "true", "bool", "Edge computing enabled")
.addConfig("cloud_sync", "auto", "string", "Cloud synchronization mode")
.build();
BatchDefaultConfigResponse result = defaultConfigService.batchUpdateDefaultConfigs(complexBatch);
// Detailed result analysis
if (result.getSuccess() == complexBatch.getConfigs().size()) {
log.info("✅ All {} configurations processed successfully", result.getSuccess());
} else if (result.getSuccess() > 0) {
log.warn("⚠️ Partial success: {} succeeded, {} failed", result.getSuccess(), result.getFailed());
// Analyze what succeeded vs failed
if (result.getProcessedItems() != null) {
Map<String, Long> statusCounts = result.getProcessedItems().stream()
.collect(Collectors.groupingBy(
ProcessedConfigItem::getStatus,
Collectors.counting()
));
log.info("Processing breakdown: {}", statusCounts);
}
} else {
log.error("❌ All configurations failed to process");
}
// Handle different types of conflicts
if (result.getConflicts() != null) {
Map<String, List<DefaultConfigConflict>> conflictsByType = result.getConflicts().stream()
.collect(Collectors.groupingBy(DefaultConfigConflict::getConflictType));
conflictsByType.forEach((conflictType, conflicts) -> {
log.warn("Conflict type '{}' affects {} configurations:", conflictType, conflicts.size());
conflicts.forEach(conflict ->
log.warn(" {} affects {} devices", conflict.getConfigKey(), conflict.getDeviceCount())
);
});
}
} catch (Exception e) {
log.error("Batch default configuration operation failed", e);
// Implement retry logic or fallback behavior as needed
}
```
#### Fallback Cache Management for Default Configurations
```java
@Autowired
private IntegrationFallbackService fallbackService;
// Check fallback cache status for default configurations
boolean hasDefaultListCache = fallbackService.hasFallbackCache("zt-device", "defaults:list:1:10");
boolean hasSpecificConfigCache = fallbackService.hasFallbackCache("zt-device", "defaults:config:resolution");
// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-device");
log.info("Default config fallback cache: {} items, TTL: {} days",
stats.getTotalCacheCount(), stats.getFallbackTtlDays());
// Clear specific default configuration cache
fallbackService.clearFallbackCache("zt-device", "defaults:config:resolution");
// Clear all default configuration caches
fallbackService.clearAllFallbackCache("zt-device");
```
### Default Configuration Types and Common Keys
#### Video Configuration Defaults
- `resolution`: Video resolution ("1920x1080", "3840x2160", "1280x720")
- `frameRate`: Video frame rate (integer: 15, 25, 30, 60)
- `codec`: Video codec ("H264", "H265", "MJPEG")
- `bitrate`: Video bitrate in bps (integer)
- `quality`: Video quality level ("low", "medium", "high", "ultra")
#### Network Configuration Defaults
- `protocol`: Network protocol ("RTSP", "HTTP", "ONVIF")
- `port`: Network port (integer: 554, 80, 8080)
- `timeout`: Connection timeout in seconds (integer)
- `retry_count`: Maximum retry attempts (integer)
#### Authentication Defaults
- `username`: Default username (string)
- `password`: Default password (string)
- `auth_method`: Authentication method ("basic", "digest", "none")
#### Storage and Recording Defaults
- `storage_path`: Default storage path (string)
- `recording_enabled`: Enable recording (boolean)
- `retention_days`: Storage retention period (integer)
- `max_file_size`: Maximum file size in MB (integer)
#### Feature Control Defaults
- `motion_detection`: Enable motion detection (boolean)
- `night_vision`: Enable night vision (boolean)
- `audio_enabled`: Enable audio recording (boolean)
- `ptz_enabled`: Enable PTZ control (boolean)
- `ai_analysis`: AI analysis features ("enabled", "disabled", "auto")
### Error Handling and Responses
#### HTTP Status Codes
- **200 OK**: Configuration retrieved/updated successfully
- **201 Created**: New configuration created successfully
- **202 Accepted**: Operation completed with conflicts (check response for details)
- **400 Bad Request**: Invalid request parameters or validation errors
- **404 Not Found**: Configuration key not found
- **409 Conflict**: Configuration conflicts prevent operation (includes conflict details)
#### Conflict Resolution
When updating default configurations that are actively used by devices, the API performs conflict detection:
1. **Type Conflicts**: Changing configuration type when devices use different types
2. **Value Validation**: Ensuring new values are compatible with existing device configurations
3. **Dependency Conflicts**: Checking for configuration dependencies and relationships
The response includes detailed conflict information to help resolve issues:
```java
// Example conflict handling
DefaultConfigConflict conflict = updateResult;
if (conflict != null) {
switch (conflict.getConflictType()) {
case "TYPE_MISMATCH":
log.warn("Type conflict: {} devices using '{}' type, proposed '{}'type",
conflict.getDeviceCount(), conflict.getCurrentType(), conflict.getProposedType());
// Handle type conversion or device updates
break;
case "VALUE_RANGE":
log.warn("Value range conflict for key '{}' affects {} devices",
conflict.getConfigKey(), conflict.getDeviceCount());
// Handle value range adjustments
break;
case "DEPENDENCY":
log.warn("Dependency conflict detected for '{}'", conflict.getConfigKey());
// Handle dependency resolution
break;
}
}
```
### Enhanced Batch Configuration API ### Enhanced Batch Configuration API
Device Integration now supports an enhanced batch configuration API that provides detailed processing results and supports default configuration rules. Device Integration now supports an enhanced batch configuration API that provides detailed processing results and supports default configuration rules.
@@ -432,6 +783,23 @@ Each processed item includes:
- **IPC**: IP Camera devices for video monitoring - **IPC**: IP Camera devices for video monitoring
- **CUSTOM**: Custom device types for sensors, controllers, etc. - **CUSTOM**: Custom device types for sensors, controllers, etc.
### Testing Default Configuration Integration
```bash
# Run default configuration integration tests
mvn test -Dtest=DefaultConfigIntegrationServiceTest
# Run all device integration tests (including default configs)
mvn test -Dtest="com.ycwl.basic.integration.device.*Test"
# Enable example runner in application-dev.yml
integration:
device:
example:
default-config:
enabled: true
```
### Common Configuration Keys ### Common Configuration Keys
- `ip_address`: Device IP address - `ip_address`: Device IP address
- `resolution`: Video resolution (e.g., "1920x1080", "3840x2160") - `resolution`: Video resolution (e.g., "1920x1080", "3840x2160")

View File

@@ -0,0 +1,54 @@
package com.ycwl.basic.integration.device.client;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.defaults.*;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 默认配置管理 Feign 客户端
*/
@FeignClient(name = "zt-device", contextId = "device-default-config", path = "/api/device/config/v2/defaults")
public interface DefaultConfigClient {
/**
* 获取默认配置列表
*/
@GetMapping
PageResponse<DefaultConfigResponse> listDefaultConfigs(@RequestParam(value = "page", defaultValue = "1") int page,
@RequestParam(value = "pageSize", defaultValue = "10") int pageSize);
/**
* 根据配置键获取默认配置
*/
@GetMapping("/{configKey}")
CommonResponse<DefaultConfigResponse> getDefaultConfig(@PathVariable("configKey") String configKey);
/**
* 创建默认配置
*/
@PostMapping
CommonResponse<String> createDefaultConfig(@RequestBody DefaultConfigRequest request);
/**
* 更新默认配置
*/
@PutMapping("/{configKey}")
CommonResponse<Map<String, Object>> updateDefaultConfig(@PathVariable("configKey") String configKey,
@RequestBody Map<String, Object> updates);
/**
* 删除默认配置
*/
@DeleteMapping("/{configKey}")
CommonResponse<String> deleteDefaultConfig(@PathVariable("configKey") String configKey);
/**
* 批量更新默认配置
*/
@PostMapping("/batch")
CommonResponse<BatchDefaultConfigResponse> batchUpdateDefaultConfigs(@RequestBody BatchDefaultConfigRequest request);
}

View File

@@ -0,0 +1,18 @@
package com.ycwl.basic.integration.device.dto.defaults;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* 批量默认配置操作请求模型
*/
@Data
public class BatchDefaultConfigRequest {
@NotEmpty(message = "配置列表不能为空")
@Valid
private List<DefaultConfigRequest> configs;
}

View File

@@ -0,0 +1,23 @@
package com.ycwl.basic.integration.device.dto.defaults;
import com.ycwl.basic.integration.device.dto.config.ProcessedConfigItem;
import lombok.Data;
import java.util.List;
/**
* 批量默认配置操作响应模型
*/
@Data
public class BatchDefaultConfigResponse {
private Integer success;
private Integer failed;
private List<DefaultConfigConflict> conflicts;
private List<ProcessedConfigItem> processedItems;
private List<String> errors;
}

View File

@@ -0,0 +1,24 @@
package com.ycwl.basic.integration.device.dto.defaults;
import lombok.Data;
import java.util.List;
/**
* 冲突信息模型
*/
@Data
public class DefaultConfigConflict {
private String configKey;
private String conflictType;
private Integer deviceCount;
private String currentType;
private String proposedType;
private List<Long> conflictDevices;
}

View File

@@ -0,0 +1,26 @@
package com.ycwl.basic.integration.device.dto.defaults;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 默认配置请求模型
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DefaultConfigRequest {
@NotBlank(message = "配置键不能为空")
private String configKey;
@NotBlank(message = "配置值不能为空")
private String configValue;
@NotBlank(message = "配置类型不能为空")
private String configType;
@NotBlank(message = "配置描述不能为空")
private String description;
}

View File

@@ -0,0 +1,28 @@
package com.ycwl.basic.integration.device.dto.defaults;
import lombok.Data;
/**
* 默认配置响应模型
*/
@Data
public class DefaultConfigResponse {
private String id;
private String configKey;
private String configValue;
private String configType;
private String description;
private Integer isActive;
private String createTime;
private String updateTime;
private Integer usageCount;
}

View File

@@ -0,0 +1,275 @@
package com.ycwl.basic.integration.device.example;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.defaults.*;
import com.ycwl.basic.integration.device.service.DefaultConfigIntegrationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 默认配置集成服务使用示例
*
* 通过在 application.yml 中设置 integration.device.example.default-config.enabled=true 来启用
*/
@Slf4j
@Component
@RequiredArgsConstructor
@ConditionalOnProperty(name = "integration.device.example.default-config.enabled", havingValue = "true")
public class DefaultConfigIntegrationExample implements CommandLineRunner {
private final DefaultConfigIntegrationService defaultConfigService;
@Override
public void run(String... args) throws Exception {
log.info("=== 默认配置集成服务使用示例 ===");
try {
// 1. 基础查询操作示例(支持自动 Fallback)
basicQueryExamples();
// 2. 配置管理操作示例(直接操作)
configManagementExamples();
// 3. 批量操作示例
batchOperationExamples();
// 4. 高级使用模式示例
advancedUsageExamples();
} catch (Exception e) {
log.error("默认配置集成示例执行失败", e);
}
}
/**
* 基础查询操作示例(支持自动 Fallback)
*/
private void basicQueryExamples() {
log.info("--- 基础查询操作示例(支持自动 Fallback)---");
try {
// 获取默认配置列表(自动缓存,服务不可用时返回缓存数据)
PageResponse<DefaultConfigResponse> configList = defaultConfigService.listDefaultConfigs(1, 10);
log.info("默认配置列表: 总数={}, 当前页配置数={}",
configList.getData().getTotal(), configList.getData().getList().size());
// 显示配置详情
for (DefaultConfigResponse config : configList.getData().getList()) {
log.info("配置详情: key={}, value={}, type={}, description={}",
config.getConfigKey(), config.getConfigValue(),
config.getConfigType(), config.getDescription());
// 获取单个配置详情(自动缓存,服务不可用时返回缓存数据)
DefaultConfigResponse detailConfig = defaultConfigService.getDefaultConfig(config.getConfigKey());
if (detailConfig != null) {
log.info("配置详情获取成功: usageCount={}, isActive={}",
detailConfig.getUsageCount(), detailConfig.getIsActive());
}
break; // 只展示第一个
}
} catch (Exception e) {
log.error("基础查询操作失败", e);
}
}
/**
* 配置管理操作示例(直接操作)
*/
private void configManagementExamples() {
log.info("--- 配置管理操作示例(直接操作)---");
String testConfigKey = "example_test_config";
try {
// 1. 创建默认配置(直接操作,失败时立即报错)
DefaultConfigRequest createRequest = new DefaultConfigRequest();
createRequest.setConfigKey(testConfigKey);
createRequest.setConfigValue("1920x1080");
createRequest.setConfigType("string");
createRequest.setDescription("示例测试配置 - 默认分辨率");
boolean createResult = defaultConfigService.createDefaultConfig(createRequest);
log.info("创建默认配置结果: {}", createResult ? "成功" : "失败");
// 2. 更新默认配置(直接操作,可能返回冲突信息)
Map<String, Object> updates = new HashMap<>();
updates.put("configValue", "3840x2160");
updates.put("description", "更新后的默认分辨率 - 4K");
DefaultConfigConflict conflict = defaultConfigService.updateDefaultConfig(testConfigKey, updates);
if (conflict != null) {
log.warn("更新配置存在冲突: configKey={}, conflictType={}, deviceCount={}",
conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
} else {
log.info("配置更新成功,无冲突");
}
// 3. 验证更新结果
DefaultConfigResponse updatedConfig = defaultConfigService.getDefaultConfig(testConfigKey);
if (updatedConfig != null) {
log.info("更新后配置值: {}", updatedConfig.getConfigValue());
}
// 4. 删除测试配置(直接操作)
boolean deleteResult = defaultConfigService.deleteDefaultConfig(testConfigKey);
log.info("删除默认配置结果: {}", deleteResult ? "成功" : "失败");
} catch (Exception e) {
log.error("配置管理操作失败", e);
}
}
/**
* 批量操作示例
*/
private void batchOperationExamples() {
log.info("--- 批量操作示例 ---");
try {
// 1. 使用构建器模式创建批量配置
BatchDefaultConfigRequest batchRequest = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("1920x1080", 30, "H264") // 添加视频配置组
.addNetworkConfig("192.168.1.100", 554, "RTSP") // 添加网络配置组
.addConfig("recording_enabled", "true", "bool", "是否启用录制")
.addConfig("storage_path", "/data/recordings", "string", "录制存储路径")
.addConfig("max_file_size", "1024", "int", "最大文件大小(MB)")
.build();
log.info("准备批量创建 {} 个默认配置", batchRequest.getConfigs().size());
// 2. 执行批量更新(直接操作)
BatchDefaultConfigResponse batchResult = defaultConfigService.batchUpdateDefaultConfigs(batchRequest);
// 3. 处理批量结果
log.info("批量操作结果: 成功={}, 失败={}", batchResult.getSuccess(), batchResult.getFailed());
if (batchResult.getConflicts() != null && !batchResult.getConflicts().isEmpty()) {
log.warn("发现 {} 个配置冲突:", batchResult.getConflicts().size());
for (DefaultConfigConflict conflict : batchResult.getConflicts()) {
log.warn("冲突配置: key={}, type={}, deviceCount={}",
conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
}
}
if (batchResult.getProcessedItems() != null) {
log.info("处理详情:");
batchResult.getProcessedItems().forEach(item ->
log.info(" 配置 {}: status={}, action={}, finalType={}",
item.getConfigKey(), item.getStatus(), item.getAction(), item.getFinalType())
);
}
if (batchResult.getErrors() != null && !batchResult.getErrors().isEmpty()) {
log.error("批量操作错误:");
batchResult.getErrors().forEach(error -> log.error(" {}", error));
}
} catch (Exception e) {
log.error("批量操作失败", e);
}
}
/**
* 高级使用模式示例
*/
private void advancedUsageExamples() {
log.info("--- 高级使用模式示例 ---");
try {
// 1. 设备类型特定的默认配置模式
createDeviceTypeSpecificConfigs();
// 2. 配置验证和完整性检查模式
validateConfigCompleteness();
// 3. 配置迁移和批量更新模式
configMigrationPattern();
} catch (Exception e) {
log.error("高级使用模式示例失败", e);
}
}
/**
* 创建设备类型特定的默认配置
*/
private void createDeviceTypeSpecificConfigs() {
log.info("创建设备类型特定的默认配置...");
// IPC摄像头默认配置
BatchDefaultConfigRequest ipcDefaults = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("1920x1080", 25, "H264")
.addConfig("night_vision", "true", "bool", "夜视功能")
.addConfig("motion_detection", "true", "bool", "移动检测")
.addConfig("stream_profile", "main", "string", "码流类型")
.build();
// NVR设备默认配置
BatchDefaultConfigRequest nvrDefaults = defaultConfigService.createBatchConfigBuilder()
.addConfig("max_channels", "16", "int", "最大通道数")
.addConfig("storage_mode", "continuous", "string", "存储模式")
.addConfig("backup_enabled", "true", "bool", "备份启用")
.build();
log.info("IPC默认配置项数: {}, NVR默认配置项数: {}",
ipcDefaults.getConfigs().size(), nvrDefaults.getConfigs().size());
}
/**
* 配置验证和完整性检查
*/
private void validateConfigCompleteness() {
log.info("验证配置完整性...");
// 获取所有默认配置
PageResponse<DefaultConfigResponse> allConfigs = defaultConfigService.listDefaultConfigs(1, 100);
// 检查必需的基础配置是否存在
String[] requiredConfigs = {"resolution", "frameRate", "codec", "protocol"};
for (String requiredConfig : requiredConfigs) {
boolean exists = allConfigs.getData().getList().stream()
.anyMatch(config -> requiredConfig.equals(config.getConfigKey()));
log.info("必需配置 {} 存在: {}", requiredConfig, exists ? "" : "");
}
// 统计配置类型分布
Map<String, Long> typeDistribution = new HashMap<>();
allConfigs.getData().getList().forEach(config ->
typeDistribution.merge(config.getConfigType(), 1L, Long::sum)
);
log.info("配置类型分布: {}", typeDistribution);
}
/**
* 配置迁移和批量更新模式
*/
private void configMigrationPattern() {
log.info("配置迁移模式示例...");
try {
// 1. 获取需要升级的配置
PageResponse<DefaultConfigResponse> oldConfigs = defaultConfigService.listDefaultConfigs(1, 50);
// 2. 创建升级配置批次
BatchDefaultConfigRequest upgradeRequest = defaultConfigService.createBatchConfigBuilder()
.addConfig("api_version", "v2", "string", "API版本")
.addConfig("security_mode", "enhanced", "string", "安全模式")
.build();
// 3. 执行批量升级
BatchDefaultConfigResponse upgradeResult = defaultConfigService.batchUpdateDefaultConfigs(upgradeRequest);
log.info("配置升级结果: 成功={}, 失败={}", upgradeResult.getSuccess(), upgradeResult.getFailed());
} catch (Exception e) {
log.warn("配置迁移示例执行失败(这是正常的,因为是示例代码)", e);
}
}
}

View File

@@ -0,0 +1,230 @@
package com.ycwl.basic.integration.device.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.device.client.DefaultConfigClient;
import com.ycwl.basic.integration.device.dto.defaults.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* 默认配置集成服务
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DefaultConfigIntegrationService {
private final DefaultConfigClient defaultConfigClient;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-device";
/**
* 获取默认配置列表(支持 Fallback)
*/
public PageResponse<DefaultConfigResponse> listDefaultConfigs(int page, int pageSize) {
return fallbackService.executeWithFallback(
SERVICE_NAME,
"defaults:list:" + page + ":" + pageSize,
() -> {
PageResponse<DefaultConfigResponse> response = defaultConfigClient.listDefaultConfigs(page, pageSize);
return handlePageResponse(response, "获取默认配置列表失败");
},
PageResponse.class
);
}
/**
* 根据配置键获取默认配置(支持 Fallback)
*/
public DefaultConfigResponse getDefaultConfig(String configKey) {
return fallbackService.executeWithFallback(
SERVICE_NAME,
"defaults:config:" + configKey,
() -> {
log.info("获取默认配置, configKey: {}", configKey);
CommonResponse<DefaultConfigResponse> response = defaultConfigClient.getDefaultConfig(configKey);
return handleResponse(response, "获取默认配置失败");
},
DefaultConfigResponse.class
);
}
/**
* 创建默认配置(直接操作,不支持 Fallback)
*/
public boolean createDefaultConfig(DefaultConfigRequest request) {
log.info("创建默认配置, configKey: {}", request.getConfigKey());
CommonResponse<String> response = defaultConfigClient.createDefaultConfig(request);
String result = handleResponse(response, "创建默认配置失败");
return result != null;
}
/**
* 更新默认配置(直接操作,不支持 Fallback)
*/
public DefaultConfigConflict updateDefaultConfig(String configKey, Map<String, Object> updates) {
log.info("更新默认配置, configKey: {}, updates: {}", configKey, updates);
CommonResponse<Map<String, Object>> response = defaultConfigClient.updateDefaultConfig(configKey, updates);
Map<String, Object> result = handleResponse(response, "更新默认配置失败");
// 检查是否有冲突信息
if (result != null && result.containsKey("conflict")) {
Object conflictObj = result.get("conflict");
if (conflictObj instanceof Map) {
// 将Map转换为DefaultConfigConflict对象
return mapToDefaultConfigConflict((Map<String, Object>) conflictObj);
}
}
return null;
}
/**
* 删除默认配置(直接操作,不支持 Fallback)
*/
public boolean deleteDefaultConfig(String configKey) {
log.info("删除默认配置, configKey: {}", configKey);
CommonResponse<String> response = defaultConfigClient.deleteDefaultConfig(configKey);
String result = handleResponse(response, "删除默认配置失败");
return result != null;
}
/**
* 批量更新默认配置(直接操作,不支持 Fallback)
*/
public BatchDefaultConfigResponse batchUpdateDefaultConfigs(BatchDefaultConfigRequest request) {
log.info("批量更新默认配置, configs count: {}", request.getConfigs().size());
CommonResponse<BatchDefaultConfigResponse> response = defaultConfigClient.batchUpdateDefaultConfigs(request);
return handleResponse(response, "批量更新默认配置失败");
}
/**
* 创建批量配置请求构建器
*/
public BatchDefaultConfigRequestBuilder createBatchConfigBuilder() {
return new BatchDefaultConfigRequestBuilder();
}
/**
* 批量配置请求构建器
*/
public static class BatchDefaultConfigRequestBuilder {
private final BatchDefaultConfigRequest request = new BatchDefaultConfigRequest();
public BatchDefaultConfigRequestBuilder() {
request.setConfigs(new ArrayList<>());
}
/**
* 添加配置项
*/
public BatchDefaultConfigRequestBuilder addConfig(String configKey, String configValue,
String configType, String description) {
DefaultConfigRequest item = new DefaultConfigRequest();
item.setConfigKey(configKey);
item.setConfigValue(configValue);
item.setConfigType(configType);
item.setDescription(description);
request.getConfigs().add(item);
return this;
}
/**
* 添加视频配置
*/
public BatchDefaultConfigRequestBuilder addVideoConfig(String resolution, Integer frameRate, String codec) {
addConfig("resolution", resolution, "string", "视频分辨率");
addConfig("frameRate", frameRate.toString(), "int", "视频帧率");
addConfig("codec", codec, "string", "视频编码格式");
return this;
}
/**
* 添加网络配置
*/
public BatchDefaultConfigRequestBuilder addNetworkConfig(String ipAddress, Integer port, String protocol) {
addConfig("ipAddress", ipAddress, "string", "IP地址");
addConfig("port", port.toString(), "int", "端口号");
addConfig("protocol", protocol, "string", "网络协议");
return this;
}
/**
* 构建请求对象
*/
public BatchDefaultConfigRequest build() {
return request;
}
}
/**
* 将Map转换为DefaultConfigConflict对象
*/
@SuppressWarnings("unchecked")
private DefaultConfigConflict mapToDefaultConfigConflict(Map<String, Object> map) {
DefaultConfigConflict conflict = new DefaultConfigConflict();
if (map.containsKey("configKey")) {
conflict.setConfigKey((String) map.get("configKey"));
}
if (map.containsKey("conflictType")) {
conflict.setConflictType((String) map.get("conflictType"));
}
if (map.containsKey("deviceCount")) {
Object deviceCount = map.get("deviceCount");
if (deviceCount instanceof Number) {
conflict.setDeviceCount(((Number) deviceCount).intValue());
}
}
if (map.containsKey("currentType")) {
conflict.setCurrentType((String) map.get("currentType"));
}
if (map.containsKey("proposedType")) {
conflict.setProposedType((String) map.get("proposedType"));
}
if (map.containsKey("conflictDevices")) {
Object conflictDevices = map.get("conflictDevices");
if (conflictDevices instanceof Iterable) {
conflict.setConflictDevices(new ArrayList<>());
for (Object deviceId : (Iterable<?>) conflictDevices) {
if (deviceId instanceof Number) {
conflict.getConflictDevices().add(((Number) deviceId).longValue());
}
}
}
}
return conflict;
}
private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
if (response == null || !response.isSuccess()) {
String msg = response != null && response.getMessage() != null
? response.getMessage()
: errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, SERVICE_NAME);
}
return response.getData();
}
private <T> PageResponse<T> handlePageResponse(PageResponse<T> response, String errorMessage) {
if (response == null || !response.isSuccess()) {
String msg = response != null && response.getMessage() != null
? response.getMessage()
: errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, SERVICE_NAME);
}
return response;
}
}