refactor(integration): 重构集成服务的降级机制

-移除各服务自定义的降级服务类,统一降级逻辑
- 新增 IntegrationFallbackService作为通用降级服务
- 更新设备和景区服务的降级处理方式
- 优化降级缓存管理,增加统计信息和批量清理功能
- 调整 API 接口,移除扁平化批量更新等相关方法
This commit is contained in:
2025-09-02 12:24:55 +08:00
parent d35a1facbd
commit 8c8a6baa5e
13 changed files with 757 additions and 260 deletions

View File

@@ -399,21 +399,6 @@ public class DeviceV2Controller {
}
}
/**
* 扁平化批量更新设备配置
*/
@PostMapping("/{id}/config/flat-batch")
public ApiResponse<String> batchFlatUpdateDeviceConfig(@PathVariable Long id,
@RequestBody Map<String, Object> configs) {
log.info("扁平化批量更新设备配置, deviceId: {}, configs count: {}", id, configs.size());
try {
deviceConfigIntegrationService.batchFlatUpdateDeviceConfig(id, configs);
return ApiResponse.success("设备配置批量更新成功");
} catch (Exception e) {
log.error("扁平化批量更新设备配置失败, deviceId: {}", id, e);
return ApiResponse.fail("扁平化批量更新设备配置失败: " + e.getMessage());
}
}
/**
* 更新设备配置
@@ -431,27 +416,6 @@ public class DeviceV2Controller {
}
}
/**
* 配置摄像头参数(快捷方法)
*/
@PutMapping("/{id}/config/camera")
public ApiResponse<String> configureCameraParams(@PathVariable Long id, @RequestBody Map<String, Object> request) {
String ipAddress = (String) request.get("ipAddress");
String resolution = (String) request.get("resolution");
Integer framerate = request.get("framerate") != null ? Integer.valueOf(request.get("framerate").toString()) : null;
String protocol = (String) request.get("protocol");
String username = (String) request.get("username");
String password = (String) request.get("password");
log.info("配置摄像头参数, deviceId: {}, ipAddress: {}, resolution: {}", id, ipAddress, resolution);
try {
deviceConfigIntegrationService.configureCameraParams(id, ipAddress, resolution, framerate, protocol, username, password);
return ApiResponse.success("摄像头参数配置成功");
} catch (Exception e) {
log.error("配置摄像头参数失败, deviceId: {}", id, e);
return ApiResponse.fail("配置摄像头参数失败: " + e.getMessage());
}
}
/**
* 删除设备配置

View File

@@ -17,6 +17,7 @@ The integration package (`com.ycwl.basic.integration`) is responsible for extern
- **IntegrationException**: Standardized exception for integration failures
- **CommonResponse/PageResponse**: Standard response wrappers for external service calls
- **ConfigValueUtil**: Utility for handling configuration values
- **IntegrationFallbackService**: Universal fallback service for handling integration failures
#### Service-Specific Integrations
Currently implemented:
@@ -35,6 +36,91 @@ service/
└── example/ # Usage examples
```
## Integration Fallback Mechanism
### Overview
The integration package includes a comprehensive fallback mechanism that provides automatic degradation when external microservices are unavailable or return errors. This mechanism ensures system resilience and maintains service availability even when dependencies fail.
### Core Components
#### IntegrationFallbackService
Universal fallback service that handles failure degradation for all microservice integrations:
**Key Features:**
- **Automatic Fallback**: Transparently handles service failures and returns cached results
- **Configurable TTL**: Service-specific cache TTL configuration (default: 7 days)
- **Cache Management**: Comprehensive cache statistics, cleanup, and monitoring
- **Service Isolation**: Per-service cache namespacing and configuration
- **Operation Types**: Supports both query operations (return cached data) and mutation operations (ignore failures with history)
**Core Methods:**
```java
// Query operations with fallback
<T> T executeWithFallback(String serviceName, String cacheKey, Supplier<T> operation, Class<T> resultClass)
// Mutation operations with fallback
void executeWithFallback(String serviceName, String cacheKey, Runnable operation)
// Cache management
boolean hasFallbackCache(String serviceName, String cacheKey)
void clearFallbackCache(String serviceName, String cacheKey)
void clearAllFallbackCache(String serviceName)
FallbackCacheStats getFallbackCacheStats(String serviceName)
```
### Fallback Strategy
#### Query Operations (GET methods) - WITH FALLBACK
1. **Normal Execution**: Execute the primary operation
2. **Success Handling**: Store successful result in fallback cache for future degradation
3. **Failure Handling**: On failure, attempt to retrieve cached result from previous success
4. **Final Fallback**: If no cached result exists, propagate the original exception
#### Mutation Operations (PUT/POST/DELETE methods) - NO FALLBACK
1. **Direct Execution**: Execute the primary operation directly without fallback
2. **Success Handling**: Operation completes successfully
3. **Failure Handling**: Immediately propagate the original exception to caller
4. **Rationale**: Users need to know if their create/update/delete operations truly succeeded or failed
### Configuration
#### Properties Structure
```yaml
integration:
fallback:
enabled: true # Global fallback switch
cachePrefix: "integration:fallback:" # Global cache prefix
defaultTtlDays: 7 # Default cache TTL in days
# Service-specific configurations
scenic:
enabled: true # Service-specific fallback switch
ttlDays: 10 # Custom TTL for scenic service
cachePrefix: "scenic:fallback:" # Custom cache prefix (optional)
device:
enabled: true
ttlDays: 5 # Custom TTL for device service
```
#### Configuration Priority
1. **Service-specific settings**: Override global defaults when specified
2. **Global defaults**: Used when service-specific settings are not provided
3. **Hardcoded defaults**: Final fallback when no configuration is available
### Cache Key Strategy
Cache keys follow a standardized naming convention:
```
{cachePrefix}{serviceName}:{operationType}:{resourceId}
```
**Examples:**
- `integration:fallback:zt-device:device:1001` - Device info cache
- `integration:fallback:zt-device:device:config:1001` - Device config cache
- `integration:fallback:zt-scenic:scenic:2001` - Scenic info cache
- `integration:fallback:zt-scenic:scenic:flat:config:2001` - Scenic flat config cache
## Scenic Integration (ZT-Scenic Microservice)
### Key Components
@@ -45,8 +131,8 @@ service/
- **DefaultConfigClient**: Default configuration operations
#### Services
- **ScenicIntegrationService**: High-level scenic operations
- **ScenicConfigIntegrationService**: Configuration management
- **ScenicIntegrationService**: High-level scenic operations (with automatic fallback)
- **ScenicConfigIntegrationService**: Configuration management (with automatic fallback)
- **DefaultConfigIntegrationService**: Default configuration handling
#### Configuration
@@ -63,37 +149,74 @@ integration:
### Usage Examples
#### Basic Scenic Operations
#### Basic Scenic Operations (with Automatic Fallback)
```java
@Autowired
private ScenicIntegrationService scenicService;
// Get scenic with configuration
// Get scenic with configuration (automatically falls back to cache on failure)
ScenicV2WithConfigDTO scenic = scenicService.getScenicWithConfig(scenicId);
// Create new scenic
// Get scenic basic info (automatically falls back to cache on failure)
ScenicV2DTO scenicInfo = scenicService.getScenic(scenicId);
// Get flat configuration (automatically falls back to cache on failure)
Map<String, Object> config = scenicService.getScenicFlatConfig(scenicId);
// Create new scenic (direct operation, fails immediately on error)
CreateScenicRequest request = new CreateScenicRequest();
request.setName("Test Scenic");
ScenicV2DTO result = scenicService.createScenic(request);
// Filter scenics
// Update scenic (direct operation, fails immediately on error)
UpdateScenicRequest updateRequest = new UpdateScenicRequest();
updateRequest.setName("Updated Scenic");
ScenicV2DTO updated = scenicService.updateScenic(scenicId, updateRequest);
// Filter scenics (no fallback for complex queries)
ScenicFilterRequest filterRequest = new ScenicFilterRequest();
// configure filters...
ScenicFilterPageResponse response = scenicService.filterScenics(filterRequest);
```
#### Configuration Management
#### Configuration Management (with Automatic Fallback)
```java
@Autowired
private ScenicConfigIntegrationService configService;
// Get flat configuration
Map<String, Object> config = scenicService.getScenicFlatConfig(scenicId);
// Get flat configuration (automatically falls back to cache on failure)
Map<String, Object> config = configService.getFlatConfigs(scenicId);
// Batch update configurations
// Batch update configurations (direct operation, fails immediately on error)
BatchConfigRequest batchRequest = new BatchConfigRequest();
// configure batch updates...
configService.batchUpdateConfigs(scenicId, batchRequest);
BatchUpdateResponse result = configService.batchUpdateConfigs(scenicId, batchRequest);
// Batch flat update configurations (direct operation, fails immediately on error)
Map<String, Object> flatUpdates = new HashMap<>();
flatUpdates.put("max_visitors", "5000");
flatUpdates.put("opening_hours", "08:00-18:00");
BatchUpdateResponse flatResult = configService.batchFlatUpdateConfigs(scenicId, flatUpdates);
```
#### Fallback Cache Management for Scenics
```java
@Autowired
private IntegrationFallbackService fallbackService;
// Check fallback cache status
boolean hasScenicCache = fallbackService.hasFallbackCache("zt-scenic", "scenic:2001");
boolean hasConfigCache = fallbackService.hasFallbackCache("zt-scenic", "scenic:flat:configs:2001");
// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-scenic");
log.info("Scenic fallback cache: {} items, TTL: {} days", stats.getTotalCacheCount(), stats.getFallbackTtlDays());
// Clear specific cache
fallbackService.clearFallbackCache("zt-scenic", "scenic:2001");
// Clear all scenic caches
fallbackService.clearAllFallbackCache("zt-scenic");
```
## Device Integration (ZT-Device Microservice)
@@ -105,8 +228,8 @@ configService.batchUpdateConfigs(scenicId, batchRequest);
- **DeviceConfigV2Client**: Device configuration management
#### Services
- **DeviceIntegrationService**: High-level device operations
- **DeviceConfigIntegrationService**: Device configuration management
- **DeviceIntegrationService**: High-level device operations (with automatic fallback)
- **DeviceConfigIntegrationService**: Device configuration management (with automatic fallback)
#### Configuration
```yaml
@@ -122,52 +245,56 @@ integration:
### Usage Examples
#### Basic Device Operations
#### Basic Device Operations (with Automatic Fallback)
```java
@Autowired
private DeviceIntegrationService deviceService;
// Create IPC camera device
// Create IPC camera device (operation tracked for future fallback)
DeviceV2DTO ipcDevice = deviceService.createIpcDevice("前门摄像头", "CAM001", scenicId);
// Get device with configuration
// Get device with configuration (automatically falls back to cache on failure)
DeviceV2WithConfigDTO device = deviceService.getDeviceWithConfig(deviceId);
// Get device by number
// Get device by number (automatically falls back to cache on failure)
DeviceV2DTO deviceByNo = deviceService.getDeviceByNo("CAM001");
// List scenic devices
// Get basic device info (automatically falls back to cache on failure)
DeviceV2DTO basicDevice = deviceService.getDevice(deviceId);
// List scenic devices (no fallback for list operations)
DeviceV2ListResponse deviceList = deviceService.getScenicIpcDevices(scenicId, 1, 10);
// Enable/disable device
// Enable/disable device (direct operation, fails immediately on error)
deviceService.enableDevice(deviceId);
deviceService.disableDevice(deviceId);
// Update device (direct operation, fails immediately on error)
UpdateDeviceRequest updateRequest = new UpdateDeviceRequest();
updateRequest.setName("更新后的摄像头");
deviceService.updateDevice(deviceId, updateRequest);
```
#### Device Configuration Management
#### Device Configuration Management (with Automatic Fallback)
```java
@Autowired
private DeviceConfigIntegrationService configService;
// Configure camera basic parameters
configService.configureCameraBasicParams(deviceId, "192.168.1.100", "1920x1080", 30, "RTSP");
// Get device configurations (with fallback)
List<DeviceConfigV2DTO> configs = configService.getDeviceConfigs(deviceId);
// Configure camera with authentication
configService.configureCameraFullParams(deviceId, "192.168.1.100", "1920x1080", 30, "RTSP", "admin", "password");
// Set specific configuration
configService.setDeviceIpAddress(deviceId, "192.168.1.101");
configService.setDeviceResolution(deviceId, "2560x1440");
configService.setDeviceFramerate(deviceId, 60);
// Get flat configuration
// Get flat configuration (automatically falls back to cache on failure)
Map<String, Object> config = configService.getDeviceFlatConfig(deviceId);
// Batch update configurations (simple way)
Map<String, Object> batchConfigs = new HashMap<>();
batchConfigs.put("brightness", "50");
batchConfigs.put("contrast", "80");
configService.batchFlatUpdateDeviceConfig(deviceId, batchConfigs);
// Get flat configuration by device number (with fallback)
Map<String, Object> configByNo = configService.getDeviceFlatConfigByNo("CAM001");
// Batch update configurations (direct operation, fails immediately on error)
BatchDeviceConfigRequest batchRequest = configService.createBatchConfigBuilder()
.addConfig("brightness", "50")
.addConfig("contrast", "80")
.build();
configService.batchUpdateDeviceConfig(deviceId, batchRequest);
// New batch configuration API with detailed results
BatchDeviceConfigRequest request = configService.createBatchConfigBuilder()
@@ -189,20 +316,32 @@ if (result.getFailed() > 0) {
#### Device Management Patterns
```java
// Create and configure camera in one operation
// Create and configure camera in one operation (both operations direct, no fallback)
DeviceV2DTO camera = deviceService.createIpcDevice("摄像头1", "CAM001", scenicId);
configService.configureCameraFullParams(camera.getId(), "192.168.1.100", "1920x1080", 30, "RTSP", "admin", "password");
// Use batch configuration to set camera parameters (direct operation)
BatchDeviceConfigRequest cameraConfig = configService.createBatchConfigBuilder()
.addConfig("ip_address", "192.168.1.100")
.addConfig("resolution", "1920x1080")
.addConfig("framerate", "30")
.addConfig("protocol", "RTSP")
.addConfig("username", "admin")
.addConfig("password", "password")
.build();
configService.batchUpdateDeviceConfig(camera.getId(), cameraConfig);
// Get scenic camera status
DeviceV2WithConfigListResponse camerasWithConfig =
deviceService.listDevicesWithConfig(1, 100, null, null, "IPC", 1, scenicId);
// Batch update camera resolution
// Batch update camera resolution (direct operations, no fallback)
for (DeviceV2WithConfigDTO device : camerasWithConfig.getList()) {
configService.setDeviceResolution(device.getId(), "2560x1440");
BatchDeviceConfigRequest resolutionUpdate = configService.createBatchConfigBuilder()
.addConfig("resolution", "2560x1440")
.build();
configService.batchUpdateDeviceConfig(device.getId(), resolutionUpdate);
}
// Monitor device configuration completeness
// Monitor device configuration completeness (with automatic fallback)
for (DeviceV2DTO device : activeDevices.getList()) {
Map<String, Object> config = configService.getDeviceFlatConfig(device.getId());
boolean hasIpConfig = config.containsKey("ip_address");
@@ -210,6 +349,26 @@ for (DeviceV2DTO device : activeDevices.getList()) {
}
```
#### Fallback Cache Management for Devices
```java
@Autowired
private IntegrationFallbackService fallbackService;
// Check fallback cache status
boolean hasDeviceCache = fallbackService.hasFallbackCache("zt-device", "device:1001");
boolean hasConfigCache = fallbackService.hasFallbackCache("zt-device", "device:flat:config:1001");
// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-device");
log.info("Device fallback cache: {} items, TTL: {} days", stats.getTotalCacheCount(), stats.getFallbackTtlDays());
// Clear specific cache
fallbackService.clearFallbackCache("zt-device", "device:1001");
// Clear all device caches
fallbackService.clearAllFallbackCache("zt-device");
```
### Enhanced Batch Configuration API
Device Integration now supports an enhanced batch configuration API that provides detailed processing results and supports default configuration rules.
@@ -359,6 +518,24 @@ Automatically converts Feign errors to IntegrationException:
### Properties Structure
```yaml
integration:
# Fallback configuration
fallback:
enabled: true # Global fallback switch
cachePrefix: "integration:fallback:" # Global cache prefix
defaultTtlDays: 7 # Default cache TTL in days
# Service-specific fallback configurations
scenic:
enabled: true # Enable fallback for scenic service
ttlDays: 10 # Custom TTL for scenic (longer due to stable data)
# cachePrefix: "scenic:fallback:" # Optional custom prefix
device:
enabled: true # Enable fallback for device service
ttlDays: 5 # Custom TTL for device (shorter due to dynamic data)
# cachePrefix: "device:fallback:" # Optional custom prefix
# Service configurations
scenic:
enabled: true
serviceName: zt-scenic
@@ -449,10 +626,23 @@ logging:
- Provide meaningful error messages for business context
- Include service name in IntegrationException for debugging
### Fallback Strategy Best Practices
- **Query operations only**: Only apply fallback to GET operations (data retrieval)
- **No fallback for mutations**: CREATE/UPDATE/DELETE operations should fail immediately to provide clear feedback
- **Cache key design**: Use clear, hierarchical cache keys for easy identification and cleanup
- **TTL management**: Set appropriate TTL based on data freshness requirements
- **Monitoring**: Regularly check fallback cache statistics and cleanup stale entries
- **Service isolation**: Configure service-specific fallback settings based on reliability needs
- **Error transparency**: Let users know exactly when their modification operations fail
### Configuration
- Use environment-specific configuration profiles
- Set appropriate timeouts based on service characteristics
- Enable retries only when safe (idempotent operations)
- Configure fallback TTL based on business requirements:
- **Critical data**: Longer TTL (7-14 days) for essential operations
- **Volatile data**: Shorter TTL (1-3 days) for frequently changing data
- **Configuration data**: Medium TTL (5-7 days) for semi-static settings
### DTOs and Mapping
- Keep DTOs simple and focused on data transfer
@@ -462,4 +652,11 @@ logging:
### Service Layer Design
- Keep integration services focused on external service calls
- Handle response transformation and error conversion
- Avoid business logic in integration services
- Avoid business logic in integration services
- Use fallback service for resilience without changing business logic
### Cache Management Strategies
- **Proactive cleanup**: Monitor cache size and clean up periodically
- **Service-specific management**: Separate cache management per service
- **Debugging support**: Use cache statistics for troubleshooting
- **Configuration validation**: Ensure fallback configuration matches service requirements

View File

@@ -11,6 +11,11 @@ import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "integration")
public class IntegrationProperties {
/**
* 降级服务配置
*/
private FallbackConfig fallback = new FallbackConfig();
/**
* 景区服务配置
*/
@@ -70,4 +75,46 @@ public class IntegrationProperties {
private boolean retryEnabled = false;
private int maxRetries = 3;
}
@Data
public static class FallbackConfig {
/**
* 是否启用降级功能
*/
private boolean enabled = true;
/**
* 降级缓存前缀
*/
private String cachePrefix = "integration:fallback:";
/**
* 默认降级缓存TTL(天)
*/
private long defaultTtlDays = 1;
/**
* 服务特定的降级配置
*/
private ServiceFallbackConfig scenic = new ServiceFallbackConfig();
private ServiceFallbackConfig device = new ServiceFallbackConfig();
}
@Data
public static class ServiceFallbackConfig {
/**
* 是否启用此服务的降级功能
*/
private boolean enabled = true;
/**
* 服务特定的缓存TTL(天),如果为0则使用默认TTL
*/
private long ttlDays = 0;
/**
* 服务特定的缓存前缀,如果为空则使用默认前缀
*/
private String cachePrefix;
}
}

View File

@@ -0,0 +1,257 @@
package com.ycwl.basic.integration.common.service;
import com.ycwl.basic.integration.common.config.IntegrationProperties;
import com.ycwl.basic.utils.JacksonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
* 集成服务通用失败降级处理
* 提供统一的降级策略,支持所有微服务集成
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class IntegrationFallbackService {
private final RedisTemplate<String, String> redisTemplate;
private final IntegrationProperties integrationProperties;
// 默认降级缓存配置
private static final String DEFAULT_FALLBACK_PREFIX = "integration:fallback:";
private static final long DEFAULT_FALLBACK_TTL = 7; // 7天
/**
* 执行操作,失败时降级到缓存结果
*
* @param serviceName 服务名称 (如: zt-device, zt-scenic)
* @param cacheKey 缓存键
* @param operation 主要操作
* @param resultClass 结果类型
* @param <T> 结果类型
* @return 操作结果或缓存的结果
*/
public <T> T executeWithFallback(String serviceName, String cacheKey, Supplier<T> operation, Class<T> resultClass) {
try {
T result = operation.get();
if (result != null) {
// 操作成功,保存结果用于将来的降级
storeFallbackCache(serviceName, cacheKey, result);
}
return result;
} catch (Exception e) {
log.warn("[{}] 操作失败,尝试降级到缓存结果, cacheKey: {}", serviceName, cacheKey, e);
T fallbackResult = getFallbackFromCache(serviceName, cacheKey, resultClass);
if (fallbackResult == null) {
log.error("[{}] 操作失败且无缓存数据, cacheKey: {}", serviceName, cacheKey);
throw e;
}
log.info("[{}] 成功从降级缓存获取结果, cacheKey: {}", serviceName, cacheKey);
return fallbackResult;
}
}
/**
* 执行操作,失败时降级到缓存结果,无返回值版本
*
* @param serviceName 服务名称
* @param cacheKey 缓存键
* @param operation 主要操作
*/
public void executeWithFallback(String serviceName, String cacheKey, Runnable operation) {
try {
operation.run();
// 操作成功,记录成功状态
storeFallbackCache(serviceName, cacheKey + ":success", "true");
log.debug("[{}] 操作成功,已记录成功状态, cacheKey: {}", serviceName, cacheKey);
} catch (Exception e) {
log.warn("[{}] 操作失败,检查是否有历史成功记录, cacheKey: {}", serviceName, cacheKey, e);
String successRecord = getFallbackFromCache(serviceName, cacheKey + ":success", String.class);
if (successRecord == null) {
log.error("[{}] 操作失败且无历史成功记录, cacheKey: {}", serviceName, cacheKey);
throw e;
}
log.info("[{}] 操作失败但有历史成功记录,忽略此次失败, cacheKey: {}", serviceName, cacheKey);
}
}
/**
* 存储降级缓存
*/
private void storeFallbackCache(String serviceName, String cacheKey, Object value) {
try {
String fullKey = buildFullCacheKey(serviceName, cacheKey);
String jsonValue = JacksonUtil.toJSONString(value);
long ttl = getFallbackTtl(serviceName);
redisTemplate.opsForValue().set(fullKey, jsonValue, ttl, TimeUnit.DAYS);
log.debug("[{}] 存储降级缓存成功, key: {}", serviceName, fullKey);
} catch (Exception e) {
log.warn("[{}] 存储降级缓存失败, cacheKey: {}", serviceName, cacheKey, e);
}
}
/**
* 从降级缓存获取结果
*/
private <T> T getFallbackFromCache(String serviceName, String cacheKey, Class<T> resultClass) {
try {
String fullKey = buildFullCacheKey(serviceName, cacheKey);
String cachedValue = redisTemplate.opsForValue().get(fullKey);
if (cachedValue != null) {
log.debug("[{}] 从降级缓存获取结果, key: {}", serviceName, fullKey);
if (resultClass == String.class) {
return resultClass.cast(cachedValue);
}
return JacksonUtil.parseObject(cachedValue, resultClass);
}
} catch (Exception e) {
log.warn("[{}] 从降级缓存获取结果失败, cacheKey: {}", serviceName, cacheKey, e);
}
return null;
}
/**
* 清除降级缓存
*
* @param serviceName 服务名称
* @param cacheKey 缓存键
*/
public void clearFallbackCache(String serviceName, String cacheKey) {
String fullKey = buildFullCacheKey(serviceName, cacheKey);
redisTemplate.delete(fullKey);
log.debug("[{}] 清除降级缓存, key: {}", serviceName, fullKey);
}
/**
* 批量清除服务的所有降级缓存
*
* @param serviceName 服务名称
*/
public void clearAllFallbackCache(String serviceName) {
String pattern = buildFullCacheKey(serviceName, "*");
Set<String> keys = redisTemplate.keys(pattern);
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
log.info("[{}] 批量清除降级缓存,共删除 {} 个缓存项", serviceName, keys.size());
}
}
/**
* 检查是否有降级缓存
*
* @param serviceName 服务名称
* @param cacheKey 缓存键
* @return 是否存在降级缓存
*/
public boolean hasFallbackCache(String serviceName, String cacheKey) {
String fullKey = buildFullCacheKey(serviceName, cacheKey);
return Boolean.TRUE.equals(redisTemplate.hasKey(fullKey));
}
/**
* 获取服务的降级缓存统计信息
*
* @param serviceName 服务名称
* @return 缓存统计信息
*/
public FallbackCacheStats getFallbackCacheStats(String serviceName) {
String pattern = buildFullCacheKey(serviceName, "*");
Set<String> keys = redisTemplate.keys(pattern);
int totalCount = keys != null ? keys.size() : 0;
return FallbackCacheStats.builder()
.serviceName(serviceName)
.totalCacheCount(totalCount)
.cacheKeyPattern(pattern)
.fallbackTtlDays(getFallbackTtl(serviceName))
.build();
}
/**
* 构建完整的缓存键
*/
private String buildFullCacheKey(String serviceName, String cacheKey) {
String prefix = getFallbackPrefix(serviceName);
return prefix + serviceName + ":" + cacheKey;
}
/**
* 获取服务的降级缓存前缀
*/
private String getFallbackPrefix(String serviceName) {
if (!integrationProperties.getFallback().isEnabled()) {
return DEFAULT_FALLBACK_PREFIX;
}
// 获取服务特定的缓存前缀
IntegrationProperties.ServiceFallbackConfig serviceConfig = getServiceFallbackConfig(serviceName);
if (serviceConfig != null && serviceConfig.getCachePrefix() != null) {
return serviceConfig.getCachePrefix();
}
// 使用全局配置的前缀
return integrationProperties.getFallback().getCachePrefix();
}
/**
* 获取服务的降级缓存TTL
*/
private long getFallbackTtl(String serviceName) {
if (!integrationProperties.getFallback().isEnabled()) {
return DEFAULT_FALLBACK_TTL;
}
// 获取服务特定的TTL
IntegrationProperties.ServiceFallbackConfig serviceConfig = getServiceFallbackConfig(serviceName);
if (serviceConfig != null && serviceConfig.getTtlDays() > 0) {
return serviceConfig.getTtlDays();
}
// 使用全局配置的TTL
return integrationProperties.getFallback().getDefaultTtlDays();
}
/**
* 获取服务特定的降级配置
*/
private IntegrationProperties.ServiceFallbackConfig getServiceFallbackConfig(String serviceName) {
switch (serviceName.toLowerCase()) {
case "zt-scenic":
return integrationProperties.getFallback().getScenic();
case "zt-device":
return integrationProperties.getFallback().getDevice();
default:
return null;
}
}
/**
* 检查服务是否启用降级功能
*/
public boolean isFallbackEnabled(String serviceName) {
if (!integrationProperties.getFallback().isEnabled()) {
return false;
}
IntegrationProperties.ServiceFallbackConfig serviceConfig = getServiceFallbackConfig(serviceName);
return serviceConfig == null || serviceConfig.isEnabled();
}
/**
* 降级缓存统计信息
*/
@lombok.Builder
@lombok.Data
public static class FallbackCacheStats {
private String serviceName;
private int totalCacheCount;
private String cacheKeyPattern;
private long fallbackTtlDays;
}
}

View File

@@ -71,10 +71,4 @@ public interface DeviceConfigV2Client {
CommonResponse<BatchUpdateResponse> batchUpdateDeviceConfig(@PathVariable("deviceId") Long deviceId,
@RequestBody BatchDeviceConfigRequest request);
/**
* 扁平化批量更新设备配置
*/
@PostMapping("/{deviceId}/batch-flat")
CommonResponse<String> batchFlatUpdateDeviceConfig(@PathVariable("deviceId") Long deviceId,
@RequestBody Map<String, Object> configs);
}

View File

@@ -1,8 +1,8 @@
package com.ycwl.basic.integration.device.example;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService;
import com.ycwl.basic.integration.device.service.DeviceIntegrationFallbackService;
import com.ycwl.basic.integration.device.dto.device.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -11,8 +11,8 @@ import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 设备集成降级机制示例
* 演示失败降级策略的使用
* 设备集成示例(包含降级机制
* 演示设备集成和失败降级策略的使用
*/
@Slf4j
@Component
@@ -21,7 +21,9 @@ public class DeviceIntegrationFallbackExample {
private final DeviceIntegrationService deviceService;
private final DeviceConfigIntegrationService configService;
private final DeviceIntegrationFallbackService fallbackService;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-device";
/**
* 演示设备信息获取的降级机制
@@ -51,26 +53,26 @@ public class DeviceIntegrationFallbackExample {
}
/**
* 演示设备操作降级机制
* 演示设备操作(无降级机制
*/
public void deviceOperationFallbackExample() {
log.info("=== 设备操作降级示例 ===");
public void deviceOperationExample() {
log.info("=== 设备操作示例 ===");
Long deviceId = 1001L;
try {
// 设备更新操作 - 自动降级
// 设备更新操作 - 直接操作,失败时抛出异常
UpdateDeviceRequest updateRequest = new UpdateDeviceRequest();
updateRequest.setName("更新后的摄像头");
deviceService.updateDevice(deviceId, updateRequest);
log.info("设备更新操作完成");
// 设备排序更新 - 自动降级
// 设备排序更新 - 直接操作,失败时抛出异常
deviceService.updateDeviceSort(deviceId, 5);
log.info("设备排序更新完成");
} catch (Exception e) {
log.error("设备操作降级失败", e);
log.error("设备操作失败", e);
}
}
@@ -84,29 +86,39 @@ public class DeviceIntegrationFallbackExample {
String configCacheKey = "device:flat:config:1001";
// 检查降级缓存状态
boolean hasDeviceCache = fallbackService.hasFallbackCache(deviceCacheKey);
boolean hasConfigCache = fallbackService.hasFallbackCache(configCacheKey);
boolean hasDeviceCache = fallbackService.hasFallbackCache(SERVICE_NAME, deviceCacheKey);
boolean hasConfigCache = fallbackService.hasFallbackCache(SERVICE_NAME, configCacheKey);
log.info("设备降级缓存存在: {}", hasDeviceCache);
log.info("配置降级缓存存在: {}", hasConfigCache);
// 清理特定的降级缓存
if (hasDeviceCache) {
fallbackService.clearFallbackCache(deviceCacheKey);
fallbackService.clearFallbackCache(SERVICE_NAME, deviceCacheKey);
log.info("已清理设备降级缓存");
}
// 获取降级缓存统计信息
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats(SERVICE_NAME);
log.info("设备服务降级缓存统计: {}", stats);
// 批量清理所有设备降级缓存
if (stats.getTotalCacheCount() > 10) {
fallbackService.clearAllFallbackCache(SERVICE_NAME);
log.info("已批量清理所有设备降级缓存");
}
}
/**
* 运行所有降级示例
* 运行所有示例
*/
public void runAllFallbackExamples() {
log.info("开始运行设备集成降级示例...");
public void runAllExamples() {
log.info("开始运行设备集成示例...");
deviceInfoFallbackExample();
deviceOperationFallbackExample();
deviceOperationExample();
fallbackCacheManagementExample();
log.info("设备集成降级示例运行完成");
log.info("设备集成示例运行完成");
}
}

View File

@@ -2,6 +2,7 @@ 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.service.IntegrationFallbackService;
import com.ycwl.basic.integration.device.client.DeviceConfigV2Client;
import com.ycwl.basic.integration.device.dto.config.*;
import lombok.RequiredArgsConstructor;
@@ -18,7 +19,9 @@ import java.util.Map;
public class DeviceConfigIntegrationService {
private final DeviceConfigV2Client deviceConfigV2Client;
private final DeviceIntegrationFallbackService fallbackService;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-device";
public List<DeviceConfigV2DTO> getDeviceConfigs(Long deviceId) {
log.info("获取设备配置列表, deviceId: {}", deviceId);
@@ -41,6 +44,7 @@ public class DeviceConfigIntegrationService {
public Map<String, Object> getDeviceFlatConfig(Long deviceId) {
log.info("获取设备扁平化配置, deviceId: {}", deviceId);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"device:flat:config:" + deviceId,
() -> {
CommonResponse<Map<String, Object>> response = deviceConfigV2Client.getDeviceFlatConfig(deviceId);
@@ -53,6 +57,7 @@ public class DeviceConfigIntegrationService {
public Map<String, Object> getDeviceFlatConfigByNo(String deviceNo) {
log.info("根据设备编号获取扁平化配置, deviceNo: {}", deviceNo);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"device:flat:config:no:" + deviceNo,
() -> {
CommonResponse<Map<String, Object>> response = deviceConfigV2Client.getDeviceFlatConfigByNo(deviceNo);
@@ -89,6 +94,8 @@ public class DeviceConfigIntegrationService {
return handleResponse(response, "批量更新设备配置失败");
}
/**
* 获取设备特定配置值
*/

View File

@@ -1,128 +0,0 @@
package com.ycwl.basic.integration.device.service;
import com.ycwl.basic.integration.device.dto.device.*;
import com.ycwl.basic.utils.JacksonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
* 设备集成服务失败降级处理
* 提供失败时的降级策略,不使用常规缓存
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceIntegrationFallbackService {
private final RedisTemplate<String, String> redisTemplate;
// 降级缓存键前缀
private static final String FALLBACK_CACHE_PREFIX = "device:fallback:";
private static final long FALLBACK_CACHE_TTL = 7; // 7天
/**
* 执行操作,失败时降级到缓存结果
*
* @param cacheKey 缓存键
* @param operation 主要操作
* @param resultClass 结果类型
* @param <T> 结果类型
* @return 操作结果或缓存的结果
*/
public <T> T executeWithFallback(String cacheKey, Supplier<T> operation, Class<T> resultClass) {
try {
T result = operation.get();
if (result != null) {
// 操作成功,保存结果用于将来的降级
storeFallbackCache(cacheKey, result);
}
return result;
} catch (Exception e) {
log.warn("操作失败,尝试降级到缓存结果, cacheKey: {}", cacheKey, e);
return getFallbackFromCache(cacheKey, resultClass);
}
}
/**
* 执行操作,失败时降级到缓存结果,无返回值版本
*
* @param cacheKey 缓存键
* @param operation 主要操作
*/
public void executeWithFallback(String cacheKey, Runnable operation) {
try {
operation.run();
// 操作成功,记录成功状态
storeFallbackCache(cacheKey + ":success", "true");
} catch (Exception e) {
log.warn("操作失败,检查是否有历史成功记录, cacheKey: {}", cacheKey, e);
String successRecord = getFallbackFromCache(cacheKey + ":success", String.class);
if (successRecord == null) {
log.error("操作失败且无历史成功记录, cacheKey: {}", cacheKey);
throw e;
}
log.info("操作失败但有历史成功记录,忽略此次失败, cacheKey: {}", cacheKey);
}
}
/**
* 存储降级缓存
*/
private void storeFallbackCache(String cacheKey, Object value) {
try {
String key = FALLBACK_CACHE_PREFIX + cacheKey;
String jsonValue = JacksonUtil.toJSONString(value);
redisTemplate.opsForValue().set(key, jsonValue, FALLBACK_CACHE_TTL, TimeUnit.DAYS);
log.debug("存储降级缓存成功, key: {}", key);
} catch (Exception e) {
log.warn("存储降级缓存失败, cacheKey: {}", cacheKey, e);
}
}
/**
* 从降级缓存获取结果
*/
private <T> T getFallbackFromCache(String cacheKey, Class<T> resultClass) {
try {
String key = FALLBACK_CACHE_PREFIX + cacheKey;
String cachedValue = redisTemplate.opsForValue().get(key);
if (cachedValue != null) {
log.info("从降级缓存获取结果, key: {}", key);
if (resultClass == String.class) {
return resultClass.cast(cachedValue);
}
return JacksonUtil.parseObject(cachedValue, resultClass);
}
} catch (Exception e) {
log.warn("从降级缓存获取结果失败, cacheKey: {}", cacheKey, e);
}
return null;
}
/**
* 清除降级缓存
*
* @param cacheKey 缓存键
*/
public void clearFallbackCache(String cacheKey) {
String key = FALLBACK_CACHE_PREFIX + cacheKey;
redisTemplate.delete(key);
log.debug("清除降级缓存, key: {}", key);
}
/**
* 检查是否有降级缓存
*
* @param cacheKey 缓存键
* @return 是否存在降级缓存
*/
public boolean hasFallbackCache(String cacheKey) {
String key = FALLBACK_CACHE_PREFIX + cacheKey;
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
}

View File

@@ -2,6 +2,7 @@ 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.service.IntegrationFallbackService;
import com.ycwl.basic.integration.device.client.DeviceV2Client;
import com.ycwl.basic.integration.device.dto.device.*;
import lombok.RequiredArgsConstructor;
@@ -14,11 +15,14 @@ import org.springframework.stereotype.Service;
public class DeviceIntegrationService {
private final DeviceV2Client deviceV2Client;
private final DeviceIntegrationFallbackService fallbackService;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-device";
public DeviceV2DTO getDevice(Long deviceId) {
log.info("获取设备信息, deviceId: {}", deviceId);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"device:" + deviceId,
() -> {
CommonResponse<DeviceV2DTO> response = deviceV2Client.getDevice(deviceId);
@@ -31,6 +35,7 @@ public class DeviceIntegrationService {
public DeviceV2DTO getDeviceByNo(String deviceNo) {
log.info("根据设备编号获取设备信息, deviceNo: {}", deviceNo);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"device:no:" + deviceNo,
() -> {
CommonResponse<DeviceV2DTO> response = deviceV2Client.getDeviceByNo(deviceNo);
@@ -43,6 +48,7 @@ public class DeviceIntegrationService {
public DeviceV2WithConfigDTO getDeviceWithConfig(Long deviceId) {
log.info("获取设备配置信息, deviceId: {}", deviceId);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"device:config:" + deviceId,
() -> {
CommonResponse<DeviceV2WithConfigDTO> response = deviceV2Client.getDeviceWithConfig(deviceId);
@@ -55,6 +61,7 @@ public class DeviceIntegrationService {
public DeviceV2WithConfigDTO getDeviceWithConfigByNo(String deviceNo) {
log.info("根据设备编号获取设备配置信息, deviceNo: {}", deviceNo);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"device:config:no:" + deviceNo,
() -> {
CommonResponse<DeviceV2WithConfigDTO> response = deviceV2Client.getDeviceByNoWithConfig(deviceNo);
@@ -72,24 +79,14 @@ public class DeviceIntegrationService {
public void updateDevice(Long deviceId, UpdateDeviceRequest request) {
log.info("更新设备信息, deviceId: {}", deviceId);
fallbackService.executeWithFallback(
"device:update:" + deviceId,
() -> {
CommonResponse<String> response = deviceV2Client.updateDevice(deviceId, request);
handleResponse(response, "更新设备信息失败");
}
);
CommonResponse<String> response = deviceV2Client.updateDevice(deviceId, request);
handleResponse(response, "更新设备信息失败");
}
public void deleteDevice(Long deviceId) {
log.info("删除设备, deviceId: {}", deviceId);
fallbackService.executeWithFallback(
"device:delete:" + deviceId,
() -> {
CommonResponse<String> response = deviceV2Client.deleteDevice(deviceId);
handleResponse(response, "删除设备失败");
}
);
CommonResponse<String> response = deviceV2Client.deleteDevice(deviceId);
handleResponse(response, "删除设备失败");
}
public DeviceV2ListResponse listDevices(Integer page, Integer pageSize, String name, String no,

View File

@@ -13,4 +13,12 @@ public class BatchUpdateResponse {
@JsonProperty("message")
private String message;
public Integer getSuccess() {
return (updatedCount != null ? updatedCount : 0) + (createdCount != null ? createdCount : 0);
}
public Integer getFailed() {
return 0; // 当前响应格式不包含失败计数,返回0作为默认值
}
}

View File

@@ -1,9 +1,9 @@
package com.ycwl.basic.integration.scenic.example;
import com.ycwl.basic.integration.scenic.dto.config.CreateConfigRequest;
import com.ycwl.basic.integration.scenic.dto.filter.FilterCondition;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.scenic.dto.config.*;
import com.ycwl.basic.integration.scenic.dto.filter.*;
import com.ycwl.basic.integration.scenic.dto.scenic.*;
import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService;
import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService;
import lombok.RequiredArgsConstructor;
@@ -11,10 +11,12 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* ZT-Scenic集成服务使用示例
* 仅供参考,实际使用时根据业务需要调用相应的服务方法
* 景区集成示例(包含降级机制)
* 演示景区集成和失败降级策略的使用
*/
@Slf4j
@Component
@@ -23,6 +25,9 @@ public class ScenicIntegrationExample {
private final ScenicIntegrationService scenicIntegrationService;
private final ScenicConfigIntegrationService scenicConfigIntegrationService;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-scenic";
/**
* 示例:创建景区并设置配置
@@ -75,4 +80,105 @@ public class ScenicIntegrationExample {
log.error("筛选景区失败", e);
}
}
/**
* 演示基础景区操作的降级机制
*/
public void basicScenicOperationsExample() {
log.info("=== 基础景区操作示例(含降级机制) ===");
Long scenicId = 2001L;
try {
// 获取景区信息 - 自动降级
ScenicV2DTO scenic = scenicIntegrationService.getScenic(scenicId);
log.info("获取景区成功: {}", scenic.getName());
// 获取景区配置信息 - 自动降级
ScenicV2WithConfigDTO scenicWithConfig = scenicIntegrationService.getScenicWithConfig(scenicId);
log.info("获取景区配置成功,配置数量: {}", scenicWithConfig.getConfig().size());
// 获取扁平化配置 - 自动降级
Map<String, Object> flatConfig = scenicIntegrationService.getScenicFlatConfig(scenicId);
log.info("获取扁平化配置成功,配置项数量: {}", flatConfig.size());
} catch (Exception e) {
log.error("景区操作降级失败", e);
}
}
/**
* 演示景区配置管理的降级机制
*/
public void scenicConfigManagementFallbackExample() {
log.info("=== 景区配置管理示例(含降级机制) ===");
Long scenicId = 2001L;
try {
// 获取扁平化配置 - 自动降级
Map<String, Object> flatConfigs = scenicConfigIntegrationService.getFlatConfigs(scenicId);
log.info("获取扁平化配置成功,配置项数量: {}", flatConfigs.size());
// 批量更新配置 - 直接操作,失败时抛出异常
Map<String, Object> updates = new HashMap<>();
updates.put("max_visitors", "5000");
updates.put("opening_hours", "08:00-18:00");
BatchUpdateResponse result = scenicConfigIntegrationService.batchFlatUpdateConfigs(scenicId, updates);
log.info("批量更新配置完成: 成功 {}, 失败 {}", result.getSuccess(), result.getFailed());
} catch (Exception e) {
log.error("景区配置管理操作失败", e);
}
}
/**
* 演示降级缓存管理
*/
public void fallbackCacheManagementExample() {
log.info("=== 景区降级缓存管理示例 ===");
String scenicCacheKey = "scenic:2001";
String configCacheKey = "scenic:flat:configs:2001";
// 检查降级缓存状态
boolean hasScenicCache = fallbackService.hasFallbackCache(SERVICE_NAME, scenicCacheKey);
boolean hasConfigCache = fallbackService.hasFallbackCache(SERVICE_NAME, configCacheKey);
log.info("景区降级缓存存在: {}", hasScenicCache);
log.info("配置降级缓存存在: {}", hasConfigCache);
// 获取降级缓存统计信息
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats(SERVICE_NAME);
log.info("景区服务降级缓存统计: 缓存数量={}, TTL={}天",
stats.getTotalCacheCount(), stats.getFallbackTtlDays());
// 清理特定的降级缓存
if (hasScenicCache) {
fallbackService.clearFallbackCache(SERVICE_NAME, scenicCacheKey);
log.info("已清理景区降级缓存");
}
// 如果缓存过多,批量清理
if (stats.getTotalCacheCount() > 50) {
fallbackService.clearAllFallbackCache(SERVICE_NAME);
log.info("已批量清理所有景区降级缓存");
}
}
/**
* 运行所有示例
*/
public void runAllExamples() {
log.info("开始运行景区集成示例(包含降级机制)...");
createScenicWithConfig();
filterScenics();
basicScenicOperationsExample();
scenicConfigManagementFallbackExample();
fallbackCacheManagementExample();
log.info("景区集成示例运行完成");
}
}

View File

@@ -2,6 +2,7 @@ package com.ycwl.basic.integration.scenic.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.scenic.client.ScenicConfigV2Client;
import com.ycwl.basic.integration.scenic.dto.config.*;
import lombok.RequiredArgsConstructor;
@@ -17,6 +18,9 @@ import java.util.Map;
public class ScenicConfigIntegrationService {
private final ScenicConfigV2Client scenicConfigV2Client;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-scenic";
public List<ScenicConfigV2DTO> listConfigs(Long scenicId) {
log.info("获取景区配置列表, scenicId: {}", scenicId);
@@ -32,8 +36,15 @@ public class ScenicConfigIntegrationService {
public Map<String, Object> getFlatConfigs(Long scenicId) {
log.info("获取景区扁平化配置, scenicId: {}", scenicId);
CommonResponse<Map<String, Object>> response = scenicConfigV2Client.getFlatConfigs(scenicId);
return handleResponse(response, "获取景区扁平化配置失败");
return fallbackService.executeWithFallback(
SERVICE_NAME,
"scenic:flat:configs:" + scenicId,
() -> {
CommonResponse<Map<String, Object>> response = scenicConfigV2Client.getFlatConfigs(scenicId);
return handleResponse(response, "获取景区扁平化配置失败");
},
Map.class
);
}
public ScenicConfigV2DTO createConfig(Long scenicId, CreateConfigRequest request) {

View File

@@ -2,6 +2,7 @@ package com.ycwl.basic.integration.scenic.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.scenic.client.ScenicConfigV2Client;
import com.ycwl.basic.integration.scenic.client.ScenicV2Client;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterPageResponse;
@@ -25,23 +26,47 @@ public class ScenicIntegrationService {
private final ScenicV2Client scenicV2Client;
private final ScenicConfigV2Client scenicConfigV2Client;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-scenic";
public ScenicV2DTO getScenic(Long scenicId) {
log.info("获取景区信息, scenicId: {}", scenicId);
CommonResponse<ScenicV2DTO> response = scenicV2Client.getScenic(scenicId);
return handleResponse(response, "获取景区信息失败");
return fallbackService.executeWithFallback(
SERVICE_NAME,
"scenic:" + scenicId,
() -> {
CommonResponse<ScenicV2DTO> response = scenicV2Client.getScenic(scenicId);
return handleResponse(response, "获取景区信息失败");
},
ScenicV2DTO.class
);
}
public ScenicV2WithConfigDTO getScenicWithConfig(Long scenicId) {
log.info("获取景区配置信息, scenicId: {}", scenicId);
CommonResponse<ScenicV2WithConfigDTO> response = scenicV2Client.getScenicWithConfig(scenicId);
return handleResponse(response, "获取景区配置信息失败");
return fallbackService.executeWithFallback(
SERVICE_NAME,
"scenic:config:" + scenicId,
() -> {
CommonResponse<ScenicV2WithConfigDTO> response = scenicV2Client.getScenicWithConfig(scenicId);
return handleResponse(response, "获取景区配置信息失败");
},
ScenicV2WithConfigDTO.class
);
}
public Map<String, Object> getScenicFlatConfig(Long scenicId) {
log.info("获取景区扁平化配置, scenicId: {}", scenicId);
CommonResponse<Map<String, Object>> response = scenicConfigV2Client.getFlatConfigs(scenicId);
return handleResponse(response, "获取景区扁平化配置失败");
return fallbackService.executeWithFallback(
SERVICE_NAME,
"scenic:flat:config:" + scenicId,
() -> {
CommonResponse<Map<String, Object>> response = scenicConfigV2Client.getFlatConfigs(scenicId);
return handleResponse(response, "获取景区扁平化配置失败");
},
Map.class
);
}
public ScenicV2DTO createScenic(CreateScenicRequest request) {