- 新增 BatchUpdateResponse 和 ProcessedConfigItem 类用于批量更新响应 - 修改 DeviceConfigV2Client 接口返回类型为 BatchUpdateResponse - 在 DeviceConfigIntegrationService 中实现新的批量更新逻辑 - 更新 DeviceIntegrationExample 和 CLAUDE.md 文档,添加新的批量配置示例
15 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Integration Package Overview
The integration package (com.ycwl.basic.integration
) is responsible for external microservice integrations using Spring Cloud OpenFeign and Nacos service discovery. It provides a standardized approach for calling external services with proper error handling, configuration management, and response processing.
Architecture
Core Components
Common Infrastructure (com.ycwl.basic.integration.common
)
- IntegrationProperties: Centralized configuration properties for all integrations
- FeignConfig: Global Feign configuration with error decoder and request interceptors
- FeignErrorDecoder: Custom error decoder that converts Feign errors to IntegrationException
- IntegrationException: Standardized exception for integration failures
- CommonResponse/PageResponse: Standard response wrappers for external service calls
- ConfigValueUtil: Utility for handling configuration values
Service-Specific Integrations
Currently implemented:
- Scenic Integration (
com.ycwl.basic.integration.scenic
): ZT-Scenic microservice integration - Device Integration (
com.ycwl.basic.integration.device
): ZT-Device microservice integration
Integration Pattern
Each external service integration follows this structure:
service/
├── client/ # Feign clients for HTTP calls
├── config/ # Service-specific configuration
├── dto/ # Data transfer objects
├── service/ # Service layer with business logic
└── example/ # Usage examples
Scenic Integration (ZT-Scenic Microservice)
Key Components
Feign Clients
- ScenicV2Client: Main scenic operations (CRUD, filtering, listing)
- ScenicConfigV2Client: Scenic configuration management
- DefaultConfigClient: Default configuration operations
Services
- ScenicIntegrationService: High-level scenic operations
- ScenicConfigIntegrationService: Configuration management
- DefaultConfigIntegrationService: Default configuration handling
Configuration
integration:
scenic:
enabled: true
serviceName: zt-scenic
connectTimeout: 5000
readTimeout: 10000
retryEnabled: false
maxRetries: 3
Usage Examples
Basic Scenic Operations
@Autowired
private ScenicIntegrationService scenicService;
// Get scenic with configuration
ScenicV2WithConfigDTO scenic = scenicService.getScenicWithConfig(scenicId);
// Create new scenic
CreateScenicRequest request = new CreateScenicRequest();
request.setName("Test Scenic");
ScenicV2DTO result = scenicService.createScenic(request);
// Filter scenics
ScenicFilterRequest filterRequest = new ScenicFilterRequest();
// configure filters...
ScenicFilterPageResponse response = scenicService.filterScenics(filterRequest);
Configuration Management
@Autowired
private ScenicConfigIntegrationService configService;
// Get flat configuration
Map<String, Object> config = scenicService.getScenicFlatConfig(scenicId);
// Batch update configurations
BatchConfigRequest batchRequest = new BatchConfigRequest();
// configure batch updates...
configService.batchUpdateConfigs(scenicId, batchRequest);
Device Integration (ZT-Device Microservice)
Key Components
Feign Clients
- DeviceV2Client: Main device operations (CRUD, filtering, listing)
- DeviceConfigV2Client: Device configuration management
Services
- DeviceIntegrationService: High-level device operations
- DeviceConfigIntegrationService: Device configuration management
Configuration
integration:
device:
enabled: true
serviceName: zt-device
connectTimeout: 5000
readTimeout: 10000
retryEnabled: false
maxRetries: 3
Usage Examples
Basic Device Operations
@Autowired
private DeviceIntegrationService deviceService;
// Create IPC camera device
DeviceV2DTO ipcDevice = deviceService.createIpcDevice("前门摄像头", "CAM001", scenicId);
// Get device with configuration
DeviceV2WithConfigDTO device = deviceService.getDeviceWithConfig(deviceId);
// Get device by number
DeviceV2DTO deviceByNo = deviceService.getDeviceByNo("CAM001");
// List scenic devices
DeviceV2ListResponse deviceList = deviceService.getScenicIpcDevices(scenicId, 1, 10);
// Enable/disable device
deviceService.enableDevice(deviceId);
deviceService.disableDevice(deviceId);
Device Configuration Management
@Autowired
private DeviceConfigIntegrationService configService;
// Configure camera basic parameters
configService.configureCameraBasicParams(deviceId, "192.168.1.100", "1920x1080", 30, "RTSP");
// 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
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);
// New batch configuration API with detailed results
BatchDeviceConfigRequest request = configService.createBatchConfigBuilder()
.addVideoConfig("4K", 30, "H265") // Add video configuration
.addNetworkConfig("192.168.1.100", 554, "RTSP") // Add network configuration
.addAuthConfig("admin", "password") // Add authentication configuration
.addConfig("recording_enabled", "true") // Use default configuration
.addConfig("custom_setting", "value", "string", "Custom setting") // Custom configuration
.build();
BatchUpdateResponse result = configService.batchUpdateDeviceConfigWithResult(deviceId, request);
if (result.getFailed() > 0) {
// Handle partial failure
result.getProcessedItems().stream()
.filter(item -> "failed".equals(item.getStatus()))
.forEach(item -> log.warn("Config {} failed: {}", item.getConfigKey(), item.getMessage()));
}
Device Management Patterns
// Create and configure camera in one operation
DeviceV2DTO camera = deviceService.createIpcDevice("摄像头1", "CAM001", scenicId);
configService.configureCameraFullParams(camera.getId(), "192.168.1.100", "1920x1080", 30, "RTSP", "admin", "password");
// Get scenic camera status
DeviceV2WithConfigListResponse camerasWithConfig =
deviceService.listDevicesWithConfig(1, 100, null, null, "IPC", 1, scenicId);
// Batch update camera resolution
for (DeviceV2WithConfigDTO device : camerasWithConfig.getList()) {
configService.setDeviceResolution(device.getId(), "2560x1440");
}
// Monitor device configuration completeness
for (DeviceV2DTO device : activeDevices.getList()) {
Map<String, Object> config = configService.getDeviceFlatConfig(device.getId());
boolean hasIpConfig = config.containsKey("ip_address");
// log configuration status...
}
Enhanced Batch Configuration API
Device Integration now supports an enhanced batch configuration API that provides detailed processing results and supports default configuration rules.
Default Configuration Rules
The system uses device_id = 0
configurations as default templates:
- Configurations with defaults: System enforces default
config_type
anddescription
, onlyconfigValue
is updated - Configurations without defaults: Allows custom
config_type
anddescription
Usage Examples
// 1. Using Builder Pattern
BatchDeviceConfigRequest request = configService.createBatchConfigBuilder()
.addVideoConfig("1920x1080", 30, "H264") // Video settings
.addNetworkConfig("192.168.1.100", 554, "RTSP") // Network settings
.addAuthConfig("admin", "password123") // Authentication
.addConfig("recording_enabled", "true") // Use default config rule
.addConfig("custom_path", "/data", "string", "Storage path") // Custom config
.build();
BatchUpdateResponse result = configService.batchUpdateDeviceConfigWithResult(deviceId, request);
// 2. Processing Results
log.info("Batch update: {} success, {} failed", result.getSuccess(), result.getFailed());
for (ProcessedConfigItem item : result.getProcessedItems()) {
if ("success".equals(item.getStatus())) {
log.info("✅ {} updated (action: {}, hasDefault: {})",
item.getConfigKey(), item.getAction(), item.getHasDefault());
} else {
log.warn("❌ {} failed: {}", item.getConfigKey(), item.getMessage());
}
}
// 3. Error Handling
if (result.getFailed() > 0) {
result.getErrors().forEach(error -> log.warn("Error: {}", error));
}
Response Format
- 200 OK: All configurations updated successfully
- 202 Accepted: Partial success (some configurations failed)
- 400 Bad Request: All configurations failed
Each processed item includes:
status
: "success" or "failed"action
: "create" or "update"hasDefault
: Whether default configuration rules were appliedfinalType
/finalDescription
: Actually used type and description
Device Types
- IPC: IP Camera devices for video monitoring
- CUSTOM: Custom device types for sensors, controllers, etc.
Common Configuration Keys
ip_address
: Device IP addressresolution
: Video resolution (e.g., "1920x1080", "3840x2160")framerate
: Video frame rate (integer)protocol
: Communication protocol (e.g., "RTSP", "HTTP")username
: Authentication usernamepassword
: Authentication passwordbrightness
: Display brightness (0-100)contrast
: Display contrast (0-100)quality
: Video quality ("low", "medium", "high")
Adding New Service Integrations
1. Create Package Structure
com.ycwl.basic.integration.{service-name}/
├── client/
├── config/
├── dto/
├── service/
└── example/
2. Add Configuration Properties
Update IntegrationProperties
to include new service configuration:
@Data
public static class NewServiceConfig {
private boolean enabled = true;
private String serviceName = "service-name";
private int connectTimeout = 5000;
private int readTimeout = 10000;
// other configs...
}
3. Create Feign Client
@FeignClient(name = "service-name", contextId = "service-context", path = "/api/path")
public interface NewServiceClient {
@GetMapping("/endpoint")
CommonResponse<ResponseDTO> getData(@PathVariable Long id);
// other endpoints...
}
4. Implement Service Layer
@Service
@RequiredArgsConstructor
public class NewServiceIntegrationService {
private final NewServiceClient client;
public ResponseDTO getData(Long id) {
CommonResponse<ResponseDTO> response = client.getData(id);
return handleResponse(response, "Failed to get data");
}
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();
}
}
Error Handling
IntegrationException
All integration failures are wrapped in IntegrationException
:
public class IntegrationException extends RuntimeException {
private final Integer code;
private final String serviceName;
// constructors and getters...
}
FeignErrorDecoder
Automatically converts Feign errors to IntegrationException:
- Parses CommonResponse error format
- Extracts service name from method key
- Provides meaningful error messages
Configuration Management
Properties Structure
integration:
scenic:
enabled: true
serviceName: zt-scenic
connectTimeout: 5000
readTimeout: 10000
retryEnabled: false
maxRetries: 3
device:
enabled: true
serviceName: zt-device
connectTimeout: 5000
readTimeout: 10000
retryEnabled: false
maxRetries: 3
Configuration Refresh
Uses @RefreshScope
to support dynamic configuration updates without restart.
Testing Integration Services
Unit Testing
Test service layers by mocking Feign clients:
@ExtendWith(MockitoExtension.class)
class ScenicIntegrationServiceTest {
@Mock
private ScenicV2Client scenicV2Client;
@InjectMocks
private ScenicIntegrationService scenicService;
@Test
void testGetScenic() {
// Mock response
CommonResponse<ScenicV2DTO> response = new CommonResponse<>();
response.setSuccess(true);
response.setData(new ScenicV2DTO());
when(scenicV2Client.getScenic(1L)).thenReturn(response);
// Test
ScenicV2DTO result = scenicService.getScenic(1L);
assertNotNull(result);
}
}
Integration Testing
Use @SpringBootTest
with test profiles and mock external services.
Common Development Tasks
Running Integration Tests
# Run specific integration test class
mvn test -Dtest=ScenicIntegrationServiceTest
# Run all integration tests
mvn test -Dtest="com.ycwl.basic.integration.*Test"
# Run device integration tests
mvn test -Dtest=DeviceIntegrationServiceTest
mvn test -Dtest="com.ycwl.basic.integration.device.*Test"
Adding New DTOs
- Create DTO classes in the appropriate
dto
package - Follow existing patterns with proper Jackson annotations
- Use
@JsonProperty
for field mapping when needed
Debugging Integration Issues
- Enable Feign client logging in
application-dev.yml
:
logging:
level:
com.ycwl.basic.integration: DEBUG
- Check Nacos service discovery in development
- Verify service configurations and timeouts
- Review FeignErrorDecoder logs for detailed error information
Best Practices
Response Handling
- Always use the
handleResponse
pattern for consistent error handling - Provide meaningful error messages for business context
- Include service name in IntegrationException for debugging
Configuration
- Use environment-specific configuration profiles
- Set appropriate timeouts based on service characteristics
- Enable retries only when safe (idempotent operations)
DTOs and Mapping
- Keep DTOs simple and focused on data transfer
- Use proper Jackson annotations for field mapping
- Separate request/response DTOs for clarity
Service Layer Design
- Keep integration services focused on external service calls
- Handle response transformation and error conversion
- Avoid business logic in integration services