From d34603062a9ee13a14ff7e42ee15da82b580277d Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sat, 30 Aug 2025 23:24:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(integration):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E6=9C=8D=E5=8A=A1=E9=9B=86=E6=88=90=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增设备服务配置和相关客户端接口 - 实现设备和设备配置的管理功能- 添加设备监控和状态管理示例 - 优化错误处理和故障恢复机制 --- CLAUDE.md | 104 ++++- .../java/com/ycwl/basic/integration/CLAUDE.md | 397 ++++++++++++++++++ .../common/config/IntegrationProperties.java | 30 ++ .../device/client/DeviceConfigV2Client.java | 80 ++++ .../device/client/DeviceV2Client.java | 79 ++++ .../config/DeviceIntegrationConfig.java | 16 + .../dto/config/BatchDeviceConfigRequest.java | 18 + .../dto/config/CreateDeviceConfigRequest.java | 12 + .../device/dto/config/DeviceConfigV2DTO.java | 39 ++ .../dto/config/UpdateDeviceConfigRequest.java | 35 ++ .../dto/device/CreateDeviceRequest.java | 12 + .../device/dto/device/DeviceV2DTO.java | 36 ++ .../dto/device/DeviceV2ListResponse.java | 13 + .../dto/device/DeviceV2WithConfigDTO.java | 12 + .../DeviceV2WithConfigListResponse.java | 13 + .../dto/device/UpdateDeviceRequest.java | 12 + .../example/DeviceIntegrationExample.java | 243 +++++++++++ .../DeviceConfigIntegrationService.java | 188 +++++++++ .../service/DeviceIntegrationService.java | 146 +++++++ 19 files changed, 1484 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/ycwl/basic/integration/CLAUDE.md create mode 100644 src/main/java/com/ycwl/basic/integration/device/client/DeviceConfigV2Client.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/client/DeviceV2Client.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/config/DeviceIntegrationConfig.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/config/BatchDeviceConfigRequest.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/config/CreateDeviceConfigRequest.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/config/DeviceConfigV2DTO.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/config/UpdateDeviceConfigRequest.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/device/CreateDeviceRequest.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2DTO.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2ListResponse.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigDTO.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigListResponse.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/dto/device/UpdateDeviceRequest.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/example/DeviceIntegrationExample.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/service/DeviceConfigIntegrationService.java create mode 100644 src/main/java/com/ycwl/basic/integration/device/service/DeviceIntegrationService.java diff --git a/CLAUDE.md b/CLAUDE.md index 6c92571..c51a066 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -122,6 +122,15 @@ mvn test -DskipTests=false 3. 使用 `@Scheduled` 进行基于 cron 的执行 4. 遵循现有的错误处理和日志记录模式 +### 多端API架构 +应用程序通过路径前缀区分不同的客户端: +- **移动端**: `/api/mobile/*` - 针对移动应用优化的接口 +- **PC管理端**: `/api/*` - Web管理面板接口 +- **任务处理**: `/task/*` - 后台任务和渲染服务接口 +- **外部集成**: 专用集成接口(打印机、代理、viid、vpt、wvp等) + +每个端点都有对应的Controller包结构,确保API的职责分离和维护性。 + ## 价格查询系统 (Pricing Module) ### 核心架构 @@ -187,4 +196,97 @@ ProductType枚举定义了支持的商品类型: - 单元测试:每个服务类都有对应测试类 - 配置验证测试:DefaultConfigValidationTest验证default配置 - JSON序列化测试:验证复杂对象的数据库存储 -- 分页功能测试:验证PageHelper集成 \ No newline at end of file +- 分页功能测试:验证PageHelper集成 + +## 关键架构模式 + +### Repository 层模式 +项目使用Repository层抽象数据访问逻辑: +- Repository接口定义数据访问契约 +- Mapper接口处理MyBatis Plus的数据库映射 +- Service层通过Repository访问数据,避免直接依赖Mapper + +### 异常处理架构 +- **全局异常处理**: `CustomExceptionHandle` 提供统一的异常处理和响应格式 +- **业务异常**: 自定义异常类继承RuntimeException,携带业务错误码 +- **集成异常**: `IntegrationException` 专门处理外部服务调用异常 + +### 配置驱动的扩展性 +通过配置文件驱动的多供应商支持: +- 存储:本地、AWS S3、阿里云 OSS +- 支付:微信支付、聪明支付 +- 人脸识别:阿里云、百度 +每个供应商通过统一接口访问,配置切换无需代码修改。 + +### 业务层架构 +- **Service层**: 核心业务逻辑实现 +- **Biz层**: 高级业务流程编排,组合多个Service +- **Controller层**: HTTP请求处理和响应转换 +- **Repository层**: 数据访问抽象 + +### 认证和会话管理 +- **JWT**: 使用jjwt库进行身份验证 +- **Redis**: 存储会话信息和缓存 +- **BaseContextHandler**: 提供当前用户上下文访问 + +## 微服务集成架构 (Integration Package) + +### 核心架构 +位于 `com.ycwl.basic.integration` 包,使用 Spring Cloud OpenFeign 和 Nacos 实现外部微服务集成。 + +#### 通用基础设施 +- **IntegrationProperties**: 所有集成的集中配置管理 +- **FeignErrorDecoder**: 自定义错误解码器,统一错误处理 +- **IntegrationException**: 标准化集成异常 +- **CommonResponse/PageResponse**: 外部服务响应包装器 + +#### 已实现的服务集成 +- **Scenic Integration** (`integration.scenic`): ZT-Scenic 微服务集成 +- **Device Integration** (`integration.device`): ZT-Device 微服务集成 + +#### 集成模式 +每个外部服务按以下结构组织: +``` +service/ +├── client/ # Feign 客户端 +├── config/ # 服务特定配置 +├── dto/ # 数据传输对象 +├── service/ # 业务逻辑层 +└── example/ # 使用示例 +``` + +### 配置管理 +```yaml +integration: + scenic: + enabled: true + serviceName: zt-scenic + connectTimeout: 5000 + readTimeout: 10000 + device: + enabled: true + serviceName: zt-device + connectTimeout: 5000 + readTimeout: 10000 +``` + +### 使用模式 +所有集成服务使用统一的 `handleResponse` 模式进行错误处理,确保一致的异常包装和日志记录。 + +### 测试集成服务 +```bash +# 运行特定集成测试 +mvn test -Dtest=ScenicIntegrationServiceTest +mvn test -Dtest=DeviceIntegrationServiceTest + +# 运行所有集成测试 +mvn test -Dtest="com.ycwl.basic.integration.*Test" +``` + +### 调试集成问题 +启用 Feign 客户端日志: +```yaml +logging: + level: + com.ycwl.basic.integration: DEBUG +``` \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/CLAUDE.md b/src/main/java/com/ycwl/basic/integration/CLAUDE.md new file mode 100644 index 0000000..2120cad --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/CLAUDE.md @@ -0,0 +1,397 @@ +# 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 +```yaml +integration: + scenic: + enabled: true + serviceName: zt-scenic + connectTimeout: 5000 + readTimeout: 10000 + retryEnabled: false + maxRetries: 3 +``` + +### Usage Examples + +#### Basic Scenic Operations +```java +@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 +```java +@Autowired +private ScenicConfigIntegrationService configService; + +// Get flat configuration +Map 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 +```yaml +integration: + device: + enabled: true + serviceName: zt-device + connectTimeout: 5000 + readTimeout: 10000 + retryEnabled: false + maxRetries: 3 +``` + +### Usage Examples + +#### Basic Device Operations +```java +@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 +```java +@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 config = configService.getDeviceFlatConfig(deviceId); + +// Batch update configurations +Map batchConfigs = new HashMap<>(); +batchConfigs.put("brightness", "50"); +batchConfigs.put("contrast", "80"); +configService.batchFlatUpdateDeviceConfig(deviceId, batchConfigs); +``` + +#### Device Management Patterns +```java +// 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 config = configService.getDeviceFlatConfig(device.getId()); + boolean hasIpConfig = config.containsKey("ip_address"); + // log configuration status... +} +``` + +### Device Types +- **IPC**: IP Camera devices for video monitoring +- **CUSTOM**: Custom device types for sensors, controllers, etc. + +### Common Configuration Keys +- `ip_address`: Device IP address +- `resolution`: Video resolution (e.g., "1920x1080", "3840x2160") +- `framerate`: Video frame rate (integer) +- `protocol`: Communication protocol (e.g., "RTSP", "HTTP") +- `username`: Authentication username +- `password`: Authentication password +- `brightness`: 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: +```java +@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 +```java +@FeignClient(name = "service-name", contextId = "service-context", path = "/api/path") +public interface NewServiceClient { + @GetMapping("/endpoint") + CommonResponse getData(@PathVariable Long id); + // other endpoints... +} +``` + +### 4. Implement Service Layer +```java +@Service +@RequiredArgsConstructor +public class NewServiceIntegrationService { + private final NewServiceClient client; + + public ResponseDTO getData(Long id) { + CommonResponse response = client.getData(id); + return handleResponse(response, "Failed to get data"); + } + + private T handleResponse(CommonResponse 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`: +```java +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 +```yaml +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: +```java +@ExtendWith(MockitoExtension.class) +class ScenicIntegrationServiceTest { + @Mock + private ScenicV2Client scenicV2Client; + + @InjectMocks + private ScenicIntegrationService scenicService; + + @Test + void testGetScenic() { + // Mock response + CommonResponse 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 +```bash +# 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 +1. Create DTO classes in the appropriate `dto` package +2. Follow existing patterns with proper Jackson annotations +3. Use `@JsonProperty` for field mapping when needed + +### Debugging Integration Issues +1. Enable Feign client logging in `application-dev.yml`: +```yaml +logging: + level: + com.ycwl.basic.integration: DEBUG +``` + +2. Check Nacos service discovery in development +3. Verify service configurations and timeouts +4. 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 \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java b/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java index 8baa61a..c4620f8 100644 --- a/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java +++ b/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java @@ -16,6 +16,11 @@ public class IntegrationProperties { */ private ScenicConfig scenic = new ScenicConfig(); + /** + * 设备服务配置 + */ + private DeviceConfig device = new DeviceConfig(); + @Data public static class ScenicConfig { /** @@ -40,4 +45,29 @@ public class IntegrationProperties { private boolean retryEnabled = false; private int maxRetries = 3; } + + @Data + public static class DeviceConfig { + /** + * 是否启用设备服务集成 + */ + private boolean enabled = true; + + /** + * 服务名称 + */ + private String serviceName = "zt-device"; + + /** + * 超时配置(毫秒) + */ + private int connectTimeout = 5000; + private int readTimeout = 10000; + + /** + * 重试配置 + */ + private boolean retryEnabled = false; + private int maxRetries = 3; + } } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/client/DeviceConfigV2Client.java b/src/main/java/com/ycwl/basic/integration/device/client/DeviceConfigV2Client.java new file mode 100644 index 0000000..28046b8 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/client/DeviceConfigV2Client.java @@ -0,0 +1,80 @@ +package com.ycwl.basic.integration.device.client; + +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.device.dto.config.*; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@FeignClient(name = "zt-device", contextId = "device-config-v2", path = "/api/device/config/v2") +public interface DeviceConfigV2Client { + + /** + * 获取设备所有配置 + */ + @GetMapping("/{deviceId}") + CommonResponse> getDeviceConfigs(@PathVariable("deviceId") Long deviceId); + + /** + * 根据设备编号获取设备所有配置 + */ + @GetMapping("/no/{no}") + CommonResponse> getDeviceConfigsByNo(@PathVariable("no") String no); + + /** + * 获取设备特定配置 + */ + @GetMapping("/{deviceId}/key/{configKey}") + CommonResponse getDeviceConfigByKey(@PathVariable("deviceId") Long deviceId, + @PathVariable("configKey") String configKey); + + /** + * 获取设备扁平化配置 + */ + @GetMapping("/{deviceId}/flat") + CommonResponse> getDeviceFlatConfig(@PathVariable("deviceId") Long deviceId); + + /** + * 根据设备编号获取设备扁平化配置 + */ + @GetMapping("/no/{no}/flat") + CommonResponse> getDeviceFlatConfigByNo(@PathVariable("no") String no); + + /** + * 创建设备配置 + */ + @PostMapping("/{deviceId}") + CommonResponse createDeviceConfig(@PathVariable("deviceId") Long deviceId, + @RequestBody CreateDeviceConfigRequest request); + + /** + * 更新设备配置 + */ + @PutMapping("/{deviceId}/{id}") + CommonResponse updateDeviceConfig(@PathVariable("deviceId") Long deviceId, + @PathVariable("id") Long id, + @RequestBody UpdateDeviceConfigRequest request); + + /** + * 删除设备配置 + */ + @DeleteMapping("/{deviceId}/{id}") + CommonResponse deleteDeviceConfig(@PathVariable("deviceId") Long deviceId, + @PathVariable("id") Long id); + + /** + * 批量更新设备配置 + */ + @PostMapping("/{deviceId}/batch") + CommonResponse batchUpdateDeviceConfig(@PathVariable("deviceId") Long deviceId, + @RequestBody BatchDeviceConfigRequest request); + + /** + * 扁平化批量更新设备配置 + */ + @PostMapping("/{deviceId}/batch-flat") + CommonResponse batchFlatUpdateDeviceConfig(@PathVariable("deviceId") Long deviceId, + @RequestBody Map configs); +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/client/DeviceV2Client.java b/src/main/java/com/ycwl/basic/integration/device/client/DeviceV2Client.java new file mode 100644 index 0000000..106c982 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/client/DeviceV2Client.java @@ -0,0 +1,79 @@ +package com.ycwl.basic.integration.device.client; + +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.device.dto.device.*; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +@FeignClient(name = "zt-device", contextId = "device-v2", path = "/api/device/v2") +public interface DeviceV2Client { + + /** + * 获取设备核心信息 + */ + @GetMapping("/{id}") + CommonResponse getDevice(@PathVariable("id") Long id); + + /** + * 根据设备编号获取设备核心信息 + */ + @GetMapping("/no/{no}") + CommonResponse getDeviceByNo(@PathVariable("no") String no); + + /** + * 获取设备详细信息(含配置) + */ + @GetMapping("/{id}/with-config") + CommonResponse getDeviceWithConfig(@PathVariable("id") Long id); + + /** + * 根据设备编号获取设备详细信息(含配置) + */ + @GetMapping("/no/{no}/with-config") + CommonResponse getDeviceByNoWithConfig(@PathVariable("no") String no); + + /** + * 创建设备 + */ + @PostMapping("/") + CommonResponse createDevice(@RequestBody CreateDeviceRequest request); + + /** + * 更新设备 + */ + @PutMapping("/{id}") + CommonResponse updateDevice(@PathVariable("id") Long id, + @RequestBody UpdateDeviceRequest request); + + /** + * 删除设备 + */ + @DeleteMapping("/{id}") + CommonResponse deleteDevice(@PathVariable("id") Long id); + + /** + * 分页获取设备列表(核心信息) + */ + @GetMapping("/") + CommonResponse listDevices( + @RequestParam(value = "page", defaultValue = "1") Integer page, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "no", required = false) String no, + @RequestParam(value = "type", required = false) String type, + @RequestParam(value = "isActive", required = false) Integer isActive, + @RequestParam(value = "scenicId", required = false) Long scenicId); + + /** + * 分页获取设备列表(含配置) + */ + @GetMapping("/with-config") + CommonResponse listDevicesWithConfig( + @RequestParam(value = "page", defaultValue = "1") Integer page, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "no", required = false) String no, + @RequestParam(value = "type", required = false) String type, + @RequestParam(value = "isActive", required = false) Integer isActive, + @RequestParam(value = "scenicId", required = false) Long scenicId); +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/config/DeviceIntegrationConfig.java b/src/main/java/com/ycwl/basic/integration/device/config/DeviceIntegrationConfig.java new file mode 100644 index 0000000..6b4c6de --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/config/DeviceIntegrationConfig.java @@ -0,0 +1,16 @@ +package com.ycwl.basic.integration.device.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; + +@Slf4j +@Configuration +@ConditionalOnProperty(prefix = "integration.device") +public class DeviceIntegrationConfig { + + public DeviceIntegrationConfig() { + log.info("ZT-Device集成配置初始化完成"); + + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/config/BatchDeviceConfigRequest.java b/src/main/java/com/ycwl/basic/integration/device/dto/config/BatchDeviceConfigRequest.java new file mode 100644 index 0000000..ac0b7d6 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/config/BatchDeviceConfigRequest.java @@ -0,0 +1,18 @@ +package com.ycwl.basic.integration.device.dto.config; + +import lombok.Data; + +import java.util.List; + +@Data +public class BatchDeviceConfigRequest { + private List configs; + + @Data + public static class BatchDeviceConfigItem { + private String configKey; + private String configValue; + private String configType; + private String description; + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/config/CreateDeviceConfigRequest.java b/src/main/java/com/ycwl/basic/integration/device/dto/config/CreateDeviceConfigRequest.java new file mode 100644 index 0000000..6bfb523 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/config/CreateDeviceConfigRequest.java @@ -0,0 +1,12 @@ +package com.ycwl.basic.integration.device.dto.config; + +import lombok.Data; + +@Data +public class CreateDeviceConfigRequest { + private String configKey; + private String configValue; + private String configType; + private String description; + private Integer isActive; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/config/DeviceConfigV2DTO.java b/src/main/java/com/ycwl/basic/integration/device/dto/config/DeviceConfigV2DTO.java new file mode 100644 index 0000000..5fd54a5 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/config/DeviceConfigV2DTO.java @@ -0,0 +1,39 @@ +package com.ycwl.basic.integration.device.dto.config; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class DeviceConfigV2DTO { + @JsonProperty("id") + private Long id; + + @JsonProperty("deviceId") + private Long deviceId; + + @JsonProperty("configKey") + private String configKey; + + @JsonProperty("configValue") + private String configValue; + + @JsonProperty("configType") + private String configType; + + @JsonProperty("description") + private String description; + + @JsonProperty("isActive") + private Integer isActive; + + @JsonProperty("createTime") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @JsonProperty("updateTime") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/config/UpdateDeviceConfigRequest.java b/src/main/java/com/ycwl/basic/integration/device/dto/config/UpdateDeviceConfigRequest.java new file mode 100644 index 0000000..190e7b4 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/config/UpdateDeviceConfigRequest.java @@ -0,0 +1,35 @@ +package com.ycwl.basic.integration.device.dto.config; + +import lombok.Data; + +import java.util.Map; + +@Data +public class UpdateDeviceConfigRequest { + private String configKey; + private String configValue; + private String configType; + private String description; + private Integer isActive; + + // 支持灵活的字段更新 + public static UpdateDeviceConfigRequest fromMap(Map updates) { + UpdateDeviceConfigRequest request = new UpdateDeviceConfigRequest(); + if (updates.containsKey("configKey")) { + request.setConfigKey((String) updates.get("configKey")); + } + if (updates.containsKey("configValue")) { + request.setConfigValue((String) updates.get("configValue")); + } + if (updates.containsKey("configType")) { + request.setConfigType((String) updates.get("configType")); + } + if (updates.containsKey("description")) { + request.setDescription((String) updates.get("description")); + } + if (updates.containsKey("isActive")) { + request.setIsActive((Integer) updates.get("isActive")); + } + return request; + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/device/CreateDeviceRequest.java b/src/main/java/com/ycwl/basic/integration/device/dto/device/CreateDeviceRequest.java new file mode 100644 index 0000000..dc5328a --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/device/CreateDeviceRequest.java @@ -0,0 +1,12 @@ +package com.ycwl.basic.integration.device.dto.device; + +import lombok.Data; + +@Data +public class CreateDeviceRequest { + private String name; + private String no; + private String type; + private Integer isActive; + private Long scenicId; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2DTO.java b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2DTO.java new file mode 100644 index 0000000..75ce26d --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2DTO.java @@ -0,0 +1,36 @@ +package com.ycwl.basic.integration.device.dto.device; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class DeviceV2DTO { + @JsonProperty("id") + private Long id; + + @JsonProperty("name") + private String name; + + @JsonProperty("no") + private String no; + + @JsonProperty("type") + private String type; // IPC, CUSTOM + + @JsonProperty("isActive") + private Integer isActive; + + @JsonProperty("scenicId") + private Long scenicId; + + @JsonProperty("createTime") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @JsonProperty("updateTime") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2ListResponse.java b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2ListResponse.java new file mode 100644 index 0000000..819834f --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2ListResponse.java @@ -0,0 +1,13 @@ +package com.ycwl.basic.integration.device.dto.device; + +import lombok.Data; + +import java.util.List; + +@Data +public class DeviceV2ListResponse { + private List list; + private Long total; + private Integer page; + private Integer pageSize; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigDTO.java b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigDTO.java new file mode 100644 index 0000000..766677a --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigDTO.java @@ -0,0 +1,12 @@ +package com.ycwl.basic.integration.device.dto.device; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Map; + +@Data +@EqualsAndHashCode(callSuper = true) +public class DeviceV2WithConfigDTO extends DeviceV2DTO { + private Map config; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigListResponse.java b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigListResponse.java new file mode 100644 index 0000000..aec44ff --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigListResponse.java @@ -0,0 +1,13 @@ +package com.ycwl.basic.integration.device.dto.device; + +import lombok.Data; + +import java.util.List; + +@Data +public class DeviceV2WithConfigListResponse { + private List list; + private Long total; + private Integer page; + private Integer pageSize; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/device/UpdateDeviceRequest.java b/src/main/java/com/ycwl/basic/integration/device/dto/device/UpdateDeviceRequest.java new file mode 100644 index 0000000..ab818d9 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/device/UpdateDeviceRequest.java @@ -0,0 +1,12 @@ +package com.ycwl.basic.integration.device.dto.device; + +import lombok.Data; + +@Data +public class UpdateDeviceRequest { + private String name; + private String no; + private String type; + private Integer isActive; + private Long scenicId; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/example/DeviceIntegrationExample.java b/src/main/java/com/ycwl/basic/integration/device/example/DeviceIntegrationExample.java new file mode 100644 index 0000000..ce2de85 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/example/DeviceIntegrationExample.java @@ -0,0 +1,243 @@ +package com.ycwl.basic.integration.device.example; + +import com.ycwl.basic.integration.device.dto.device.*; +import com.ycwl.basic.integration.device.dto.config.*; +import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService; +import com.ycwl.basic.integration.device.service.DeviceIntegrationService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Device Integration 使用示例 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class DeviceIntegrationExample { + + private final DeviceIntegrationService deviceService; + private final DeviceConfigIntegrationService deviceConfigService; + + /** + * 基本设备操作示例 + */ + public void basicDeviceOperations() { + log.info("=== 基本设备操作示例 ==="); + + // 1. 创建IPC摄像头设备 + DeviceV2DTO ipcDevice = deviceService.createIpcDevice( + "前门摄像头", "CAM001", 1001L); + log.info("创建IPC设备: {}", ipcDevice); + + // 2. 创建自定义设备 + DeviceV2DTO customDevice = deviceService.createCustomDevice( + "温度传感器", "TEMP001", 1001L); + log.info("创建自定义设备: {}", customDevice); + + // 3. 根据ID获取设备信息 + DeviceV2DTO device = deviceService.getDevice(ipcDevice.getId()); + log.info("获取设备信息: {}", device); + + // 4. 根据设备编号获取设备信息 + DeviceV2DTO deviceByNo = deviceService.getDeviceByNo("CAM001"); + log.info("根据编号获取设备: {}", deviceByNo); + + // 5. 获取设备详细信息(含配置) + DeviceV2WithConfigDTO deviceWithConfig = deviceService.getDeviceWithConfig(ipcDevice.getId()); + log.info("获取设备配置: {}", deviceWithConfig); + + // 6. 分页查询景区设备列表 + DeviceV2ListResponse deviceList = deviceService.getScenicIpcDevices(1001L, 1, 10); + log.info("景区IPC设备列表: 总数={}, 当前页={}", deviceList.getTotal(), deviceList.getList().size()); + + // 7. 启用/禁用设备 + deviceService.enableDevice(ipcDevice.getId()); + log.info("设备已启用"); + + deviceService.disableDevice(customDevice.getId()); + log.info("设备已禁用"); + } + + /** + * 设备配置管理示例 + */ + public void deviceConfigurationOperations() { + log.info("=== 设备配置管理示例 ==="); + + // 假设已有设备ID + Long deviceId = 1L; + + // 1. 配置摄像头基本参数 + deviceConfigService.configureCameraBasicParams( + deviceId, "192.168.1.100", "1920x1080", 30, "RTSP"); + log.info("摄像头基本参数已配置"); + + // 2. 配置摄像头完整参数(包含认证) + deviceConfigService.configureCameraFullParams( + deviceId, "192.168.1.101", "3840x2160", 25, "RTSP", "admin", "password123"); + log.info("摄像头完整参数已配置"); + + // 3. 单独设置特定配置 + deviceConfigService.setDeviceIpAddress(deviceId, "192.168.1.102"); + deviceConfigService.setDeviceResolution(deviceId, "2560x1440"); + deviceConfigService.setDeviceFramerate(deviceId, 60); + log.info("单独配置项已更新"); + + // 4. 获取设备所有配置 + List configs = deviceConfigService.getDeviceConfigs(deviceId); + log.info("设备配置列表: {}", configs.size()); + + // 5. 获取扁平化配置 + Map flatConfig = deviceConfigService.getDeviceFlatConfig(deviceId); + log.info("扁平化配置: {}", flatConfig); + + // 6. 获取特定配置值 + String ipAddress = deviceConfigService.getDeviceIpAddress(deviceId); + String resolution = deviceConfigService.getDeviceResolution(deviceId); + log.info("IP地址: {}, 分辨率: {}", ipAddress, resolution); + + // 7. 批量更新配置 + Map batchConfigs = new HashMap<>(); + batchConfigs.put("brightness", "50"); + batchConfigs.put("contrast", "80"); + batchConfigs.put("quality", "high"); + deviceConfigService.batchFlatUpdateDeviceConfig(deviceId, batchConfigs); + log.info("批量配置已更新"); + } + + /** + * 摄像头管理示例 + */ + public void cameraManagementExample() { + log.info("=== 摄像头管理示例 ==="); + + Long scenicId = 1001L; + + // 1. 批量创建摄像头 + for (int i = 1; i <= 5; i++) { + DeviceV2DTO camera = deviceService.createIpcDevice( + "摄像头" + i, "CAM00" + i, scenicId); + + // 配置每个摄像头的基本参数 + deviceConfigService.configureCameraFullParams( + camera.getId(), + "192.168.1." + (100 + i), + "1920x1080", + 30, + "RTSP", + "admin", + "camera" + i + ); + log.info("创建并配置摄像头: {}", camera.getName()); + } + + // 2. 获取景区所有摄像头状态 + DeviceV2WithConfigListResponse camerasWithConfig = + deviceService.listDevicesWithConfig(1, 100, null, null, "IPC", 1, scenicId); + + log.info("景区摄像头总数: {}", camerasWithConfig.getTotal()); + for (DeviceV2WithConfigDTO camera : camerasWithConfig.getList()) { + log.info("摄像头: {}, IP: {}", + camera.getName(), + camera.getConfig().get("ip_address")); + } + + // 3. 批量更新摄像头分辨率 + for (DeviceV2WithConfigDTO camera : camerasWithConfig.getList()) { + deviceConfigService.setDeviceResolution(camera.getId(), "2560x1440"); + } + log.info("所有摄像头分辨率已更新为 2560x1440"); + } + + /** + * 设备监控和状态管理示例 + */ + public void deviceMonitoringExample() { + log.info("=== 设备监控和状态管理示例 ==="); + + Long scenicId = 1001L; + + // 1. 获取景区所有激活设备 + DeviceV2ListResponse activeDevices = deviceService.getScenicActiveDevices(scenicId, 1, 50); + log.info("景区激活设备数量: {}", activeDevices.getTotal()); + + // 2. 按设备类型分类统计 + Map deviceTypeCount = new HashMap<>(); + for (DeviceV2DTO device : activeDevices.getList()) { + deviceTypeCount.merge(device.getType(), 1, Integer::sum); + } + log.info("设备类型统计: {}", deviceTypeCount); + + // 3. 检查设备配置完整性 + for (DeviceV2DTO device : activeDevices.getList()) { + try { + Map config = deviceConfigService.getDeviceFlatConfig(device.getId()); + boolean hasIpConfig = config.containsKey("ip_address"); + log.info("设备 {} 配置状态: IP配置={}", device.getName(), hasIpConfig ? "已配置" : "未配置"); + } catch (Exception e) { + log.warn("获取设备 {} 配置失败: {}", device.getName(), e.getMessage()); + } + } + + // 4. 按设备编号搜索 + try { + DeviceV2WithConfigDTO deviceByNo = deviceService.getDeviceWithConfigByNo("CAM001"); + log.info("根据编号找到设备: {} (配置项数量: {})", + deviceByNo.getName(), + deviceByNo.getConfig().size()); + } catch (Exception e) { + log.warn("未找到设备编号 CAM001: {}", e.getMessage()); + } + } + + /** + * 错误处理和故障恢复示例 + */ + public void errorHandlingExample() { + log.info("=== 错误处理和故障恢复示例 ==="); + + // 1. 尝试获取不存在的设备 + try { + deviceService.getDevice(99999L); + } catch (Exception e) { + log.warn("获取不存在设备的预期错误: {}", e.getMessage()); + } + + // 2. 尝试获取不存在的配置 + try { + deviceConfigService.getDeviceConfigByKey(1L, "non_existent_key"); + } catch (Exception e) { + log.warn("获取不存在配置的预期错误: {}", e.getMessage()); + } + + // 3. 创建设备时的参数验证 + try { + CreateDeviceRequest invalidRequest = new CreateDeviceRequest(); + // 缺少必要字段 + deviceService.createDevice(invalidRequest); + } catch (Exception e) { + log.warn("创建设备参数错误: {}", e.getMessage()); + } + } + + /** + * 运行所有示例 + */ + public void runAllExamples() { + try { + basicDeviceOperations(); + deviceConfigurationOperations(); + cameraManagementExample(); + deviceMonitoringExample(); + errorHandlingExample(); + log.info("=== 所有示例执行完成 ==="); + } catch (Exception e) { + log.error("示例执行过程中发生错误", e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/service/DeviceConfigIntegrationService.java b/src/main/java/com/ycwl/basic/integration/device/service/DeviceConfigIntegrationService.java new file mode 100644 index 0000000..0e2359a --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/service/DeviceConfigIntegrationService.java @@ -0,0 +1,188 @@ +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.device.client.DeviceConfigV2Client; +import com.ycwl.basic.integration.device.dto.config.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service +@RequiredArgsConstructor +public class DeviceConfigIntegrationService { + + private final DeviceConfigV2Client deviceConfigV2Client; + + public List getDeviceConfigs(Long deviceId) { + log.info("获取设备配置列表, deviceId: {}", deviceId); + CommonResponse> response = deviceConfigV2Client.getDeviceConfigs(deviceId); + return handleResponse(response, "获取设备配置列表失败"); + } + + public List getDeviceConfigsByNo(String deviceNo) { + log.info("根据设备编号获取配置列表, deviceNo: {}", deviceNo); + CommonResponse> response = deviceConfigV2Client.getDeviceConfigsByNo(deviceNo); + return handleResponse(response, "根据设备编号获取配置列表失败"); + } + + public DeviceConfigV2DTO getDeviceConfigByKey(Long deviceId, String configKey) { + log.info("根据键获取设备配置, deviceId: {}, configKey: {}", deviceId, configKey); + CommonResponse response = deviceConfigV2Client.getDeviceConfigByKey(deviceId, configKey); + return handleResponse(response, "根据键获取设备配置失败"); + } + + public Map getDeviceFlatConfig(Long deviceId) { + log.info("获取设备扁平化配置, deviceId: {}", deviceId); + CommonResponse> response = deviceConfigV2Client.getDeviceFlatConfig(deviceId); + return handleResponse(response, "获取设备扁平化配置失败"); + } + + public Map getDeviceFlatConfigByNo(String deviceNo) { + log.info("根据设备编号获取扁平化配置, deviceNo: {}", deviceNo); + CommonResponse> response = deviceConfigV2Client.getDeviceFlatConfigByNo(deviceNo); + return handleResponse(response, "根据设备编号获取扁平化配置失败"); + } + + public DeviceConfigV2DTO createDeviceConfig(Long deviceId, CreateDeviceConfigRequest request) { + log.info("创建设备配置, deviceId: {}, configKey: {}", deviceId, request.getConfigKey()); + CommonResponse response = deviceConfigV2Client.createDeviceConfig(deviceId, request); + return handleResponse(response, "创建设备配置失败"); + } + + public void updateDeviceConfig(Long deviceId, Long configId, UpdateDeviceConfigRequest request) { + log.info("更新设备配置, deviceId: {}, configId: {}", deviceId, configId); + CommonResponse response = deviceConfigV2Client.updateDeviceConfig(deviceId, configId, request); + handleResponse(response, "更新设备配置失败"); + } + + public void deleteDeviceConfig(Long deviceId, Long configId) { + log.info("删除设备配置, deviceId: {}, configId: {}", deviceId, configId); + CommonResponse response = deviceConfigV2Client.deleteDeviceConfig(deviceId, configId); + handleResponse(response, "删除设备配置失败"); + } + + public void batchUpdateDeviceConfig(Long deviceId, BatchDeviceConfigRequest request) { + log.info("批量更新设备配置, deviceId: {}, configs count: {}", deviceId, request.getConfigs().size()); + CommonResponse response = deviceConfigV2Client.batchUpdateDeviceConfig(deviceId, request); + handleResponse(response, "批量更新设备配置失败"); + } + + public void batchFlatUpdateDeviceConfig(Long deviceId, Map configs) { + log.info("扁平化批量更新设备配置, deviceId: {}, configs count: {}", deviceId, configs.size()); + CommonResponse response = deviceConfigV2Client.batchFlatUpdateDeviceConfig(deviceId, configs); + handleResponse(response, "扁平化批量更新设备配置失败"); + } + + /** + * 设置设备IP地址 + */ + public void setDeviceIpAddress(Long deviceId, String ipAddress) { + Map config = new HashMap<>(); + config.put("ip_address", ipAddress); + batchFlatUpdateDeviceConfig(deviceId, config); + } + + /** + * 设置设备分辨率 + */ + public void setDeviceResolution(Long deviceId, String resolution) { + Map config = new HashMap<>(); + config.put("resolution", resolution); + batchFlatUpdateDeviceConfig(deviceId, config); + } + + /** + * 设置设备帧率 + */ + public void setDeviceFramerate(Long deviceId, Integer framerate) { + Map config = new HashMap<>(); + config.put("framerate", framerate.toString()); + batchFlatUpdateDeviceConfig(deviceId, config); + } + + /** + * 设置设备协议 + */ + public void setDeviceProtocol(Long deviceId, String protocol) { + Map config = new HashMap<>(); + config.put("protocol", protocol); + batchFlatUpdateDeviceConfig(deviceId, config); + } + + /** + * 设置设备认证信息 + */ + public void setDeviceAuth(Long deviceId, String username, String password) { + Map config = new HashMap<>(); + config.put("username", username); + config.put("password", password); + batchFlatUpdateDeviceConfig(deviceId, config); + } + + /** + * 配置摄像头基本参数 + */ + public void configureCameraBasicParams(Long deviceId, String ipAddress, String resolution, + Integer framerate, String protocol) { + Map configs = new HashMap<>(); + configs.put("ip_address", ipAddress); + configs.put("resolution", resolution); + configs.put("framerate", framerate.toString()); + configs.put("protocol", protocol); + batchFlatUpdateDeviceConfig(deviceId, configs); + } + + /** + * 配置摄像头完整参数 + */ + public void configureCameraFullParams(Long deviceId, String ipAddress, String resolution, + Integer framerate, String protocol, String username, String password) { + Map configs = new HashMap<>(); + configs.put("ip_address", ipAddress); + configs.put("resolution", resolution); + configs.put("framerate", framerate.toString()); + configs.put("protocol", protocol); + configs.put("username", username); + configs.put("password", password); + batchFlatUpdateDeviceConfig(deviceId, configs); + } + + /** + * 获取设备特定配置值 + */ + public String getDeviceConfigValue(Long deviceId, String configKey) { + DeviceConfigV2DTO config = getDeviceConfigByKey(deviceId, configKey); + return config != null ? config.getConfigValue() : null; + } + + /** + * 获取设备IP地址 + */ + public String getDeviceIpAddress(Long deviceId) { + return getDeviceConfigValue(deviceId, "ip_address"); + } + + /** + * 获取设备分辨率 + */ + public String getDeviceResolution(Long deviceId) { + return getDeviceConfigValue(deviceId, "resolution"); + } + + private T handleResponse(CommonResponse 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, "zt-device"); + } + return response.getData(); + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/service/DeviceIntegrationService.java b/src/main/java/com/ycwl/basic/integration/device/service/DeviceIntegrationService.java new file mode 100644 index 0000000..418496d --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/service/DeviceIntegrationService.java @@ -0,0 +1,146 @@ +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.device.client.DeviceV2Client; +import com.ycwl.basic.integration.device.dto.device.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class DeviceIntegrationService { + + private final DeviceV2Client deviceV2Client; + + public DeviceV2DTO getDevice(Long deviceId) { + log.info("获取设备信息, deviceId: {}", deviceId); + CommonResponse response = deviceV2Client.getDevice(deviceId); + return handleResponse(response, "获取设备信息失败"); + } + + public DeviceV2DTO getDeviceByNo(String deviceNo) { + log.info("根据设备编号获取设备信息, deviceNo: {}", deviceNo); + CommonResponse response = deviceV2Client.getDeviceByNo(deviceNo); + return handleResponse(response, "根据设备编号获取设备信息失败"); + } + + public DeviceV2WithConfigDTO getDeviceWithConfig(Long deviceId) { + log.info("获取设备配置信息, deviceId: {}", deviceId); + CommonResponse response = deviceV2Client.getDeviceWithConfig(deviceId); + return handleResponse(response, "获取设备配置信息失败"); + } + + public DeviceV2WithConfigDTO getDeviceWithConfigByNo(String deviceNo) { + log.info("根据设备编号获取设备配置信息, deviceNo: {}", deviceNo); + CommonResponse response = deviceV2Client.getDeviceByNoWithConfig(deviceNo); + return handleResponse(response, "根据设备编号获取设备配置信息失败"); + } + + public DeviceV2DTO createDevice(CreateDeviceRequest request) { + log.info("创建设备, name: {}, no: {}, type: {}", request.getName(), request.getNo(), request.getType()); + CommonResponse response = deviceV2Client.createDevice(request); + return handleResponse(response, "创建设备失败"); + } + + public void updateDevice(Long deviceId, UpdateDeviceRequest request) { + log.info("更新设备信息, deviceId: {}", deviceId); + CommonResponse response = deviceV2Client.updateDevice(deviceId, request); + handleResponse(response, "更新设备信息失败"); + } + + public void deleteDevice(Long deviceId) { + log.info("删除设备, deviceId: {}", deviceId); + CommonResponse response = deviceV2Client.deleteDevice(deviceId); + handleResponse(response, "删除设备失败"); + } + + public DeviceV2ListResponse listDevices(Integer page, Integer pageSize, String name, String no, + String type, Integer isActive, Long scenicId) { + log.info("分页查询设备列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}", + page, pageSize, name, no, type, isActive, scenicId); + CommonResponse response = deviceV2Client.listDevices( + page, pageSize, name, no, type, isActive, scenicId); + return handleResponse(response, "分页查询设备列表失败"); + } + + public DeviceV2WithConfigListResponse listDevicesWithConfig(Integer page, Integer pageSize, String name, String no, + String type, Integer isActive, Long scenicId) { + log.info("分页查询设备带配置列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}", + page, pageSize, name, no, type, isActive, scenicId); + CommonResponse response = deviceV2Client.listDevicesWithConfig( + page, pageSize, name, no, type, isActive, scenicId); + return handleResponse(response, "分页查询设备带配置列表失败"); + } + + /** + * 创建IPC摄像头设备 + */ + public DeviceV2DTO createIpcDevice(String name, String deviceNo, Long scenicId) { + CreateDeviceRequest request = new CreateDeviceRequest(); + request.setName(name); + request.setNo(deviceNo); + request.setType("IPC"); + request.setIsActive(1); + request.setScenicId(scenicId); + return createDevice(request); + } + + /** + * 创建自定义设备 + */ + public DeviceV2DTO createCustomDevice(String name, String deviceNo, Long scenicId) { + CreateDeviceRequest request = new CreateDeviceRequest(); + request.setName(name); + request.setNo(deviceNo); + request.setType("CUSTOM"); + request.setIsActive(1); + request.setScenicId(scenicId); + return createDevice(request); + } + + /** + * 启用设备 + */ + public void enableDevice(Long deviceId) { + UpdateDeviceRequest request = new UpdateDeviceRequest(); + request.setIsActive(1); + updateDevice(deviceId, request); + } + + /** + * 禁用设备 + */ + public void disableDevice(Long deviceId) { + UpdateDeviceRequest request = new UpdateDeviceRequest(); + request.setIsActive(0); + updateDevice(deviceId, request); + } + + /** + * 获取景区的IPC设备列表 + */ + public DeviceV2ListResponse getScenicIpcDevices(Long scenicId, Integer page, Integer pageSize) { + return listDevices(page, pageSize, null, null, "IPC", 1, scenicId); + } + + /** + * 获取景区的所有激活设备 + */ + public DeviceV2ListResponse getScenicActiveDevices(Long scenicId, Integer page, Integer pageSize) { + return listDevices(page, pageSize, null, null, null, 1, scenicId); + } + + private T handleResponse(CommonResponse 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, "zt-device"); + } + return response.getData(); + } +} \ No newline at end of file