From 15ca08ce14f2043a732c2dd52a3b2bb9c2beb0d0 Mon Sep 17 00:00:00 2001 From: FAN-yeB <1442100690@qq.com> Date: Wed, 17 Sep 2025 10:04:19 +0800 Subject: [PATCH] =?UTF-8?q?update=EF=BC=9A=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../device/controller/DeviceController.java | 155 +++++++++++++++++- .../service/impl/DeviceServiceImpl.java | 8 +- .../resources/db/changelog/202509161609.sql | 3 + .../db/changelog/db.changelog-master.yaml | 7 + 4 files changed, 166 insertions(+), 7 deletions(-) create mode 100644 main/manager-api/src/main/resources/db/changelog/202509161609.sql diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java index b0320e3c..65987265 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java @@ -29,15 +29,31 @@ import xiaozhi.modules.device.dto.DeviceManualAddDTO; import xiaozhi.modules.device.entity.DeviceEntity; import xiaozhi.modules.device.service.DeviceService; import xiaozhi.modules.security.user.SecurityUser; +import xiaozhi.modules.sys.service.SysParamsService; +import org.springframework.web.client.RestTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import com.fasterxml.jackson.databind.ObjectMapper; @Tag(name = "设备管理") -@AllArgsConstructor @RestController @RequestMapping("/device") public class DeviceController { private final DeviceService deviceService; - private final RedisUtils redisUtils; + private final SysParamsService sysParamsService; + private final RestTemplate restTemplate; + private final ObjectMapper objectMapper; + + public DeviceController(DeviceService deviceService, RedisUtils redisUtils, SysParamsService sysParamsService, RestTemplate restTemplate, ObjectMapper objectMapper) { + this.deviceService = deviceService; + this.redisUtils = redisUtils; + this.sysParamsService = sysParamsService; + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + } @PostMapping("/bind/{agentId}/{deviceCode}") @Operation(summary = "绑定设备") @@ -75,6 +91,87 @@ public class DeviceController { return new Result>().ok(devices); } + @PostMapping("/bind/{agentId}") + @Operation(summary = "转发POST请求到MQTT网关") + @RequiresPermissions("sys:role:normal") + public Result forwardToMqttGateway(@PathVariable String agentId, @RequestBody String requestBody) { + try { + // 从系统参数中获取MQTT网关地址 + String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true); + if (StringUtils.isBlank(mqttGatewayUrl)) { + return new Result().error("MQTT网关地址未配置"); + } + + // 获取当前用户的设备列表 + UserDetail user = SecurityUser.getUser(); + List devices = deviceService.getUserDevices(user.getId(), agentId); + + // 构建deviceIds数组 + java.util.List deviceIds = new java.util.ArrayList<>(); + for (DeviceEntity device : devices) { + String macAddress = device.getMacAddress() != null ? device.getMacAddress() : "unknown"; + String groupId = device.getBoard() != null ? device.getBoard() : "GID_default"; + + // 替换冒号为下划线 + groupId = groupId.replace(":", "_"); + macAddress = macAddress.replace(":", "_"); + + // 构建mqtt客户端ID格式:groupId@@@macAddress@@@macAddress + String mqttClientId = groupId + "@@@" + macAddress + "@@@" + macAddress; + deviceIds.add(mqttClientId); + } + + // 构建完整的URL + String url = "http://" + mqttGatewayUrl + "/api/devices/status"; + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/json"); + + // 生成Bearer令牌 + String token = generateBearerToken(); + if (token == null) { + return new Result().error("令牌生成失败"); + } + headers.set("Authorization", "Bearer " + token); + + // 构建请求体JSON + String jsonBody = "{\"deviceIds\":" + objectMapper.writeValueAsString(deviceIds) + "}"; + HttpEntity requestEntity = new HttpEntity<>(jsonBody, headers); + + // 发送POST请求 + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + + // 返回响应 + return new Result().ok(response.getBody()); + } catch (Exception e) { + return new Result().error("转发请求失败: " + e.getMessage()); + } + } + + private String generateBearerToken() { + try { + // 获取当前日期,格式为yyyy-MM-dd + String dateStr = java.time.LocalDate.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")); + + // 获取MQTT签名密钥 + String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false); + if (StringUtils.isBlank(signatureKey)) { + return null; + } + + // 将日期字符串与MQTT_SIGNATURE_KEY连接 + String tokenContent = dateStr + signatureKey; + + // 对连接后的字符串进行SHA256哈希计算 + String token = org.apache.commons.codec.digest.DigestUtils.sha256Hex(tokenContent); + + return token; + } catch (Exception e) { + return null; + } + } + @PostMapping("/unbind") @Operation(summary = "解绑设备") @RequiresPermissions("sys:role:normal") @@ -109,4 +206,58 @@ public class DeviceController { deviceService.manualAddDevice(user.getId(), dto); return new Result<>(); } + + @PostMapping("/commands/{deviceId}") + @Operation(summary = "发送设备指令") + @RequiresPermissions("sys:role:normal") + public Result sendDeviceCommand(@PathVariable String deviceId, @RequestBody String command) { + try { + // 从系统参数中获取MQTT网关地址 + String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true); + if (StringUtils.isBlank(mqttGatewayUrl)) { + return new Result().error("MQTT网关地址未配置"); + } + + // 构建完整的URL + // 获取设备信息以构建mqttClientId + DeviceEntity deviceById = deviceService.selectById(deviceId); + String macAddress = deviceById != null ? deviceById.getMacAddress() : "unknown"; + String groupId = deviceById != null ? deviceById.getBoard() : null; + if (groupId == null) { + groupId = "GID_default"; + } + groupId = groupId.replace(":", "_"); + macAddress = macAddress.replace(":", "_"); + + // 拼接为groupId@@@macAddress@@@deviceId格式 + String mqttClientId = groupId + "@@@" + macAddress + "@@@" + macAddress; + + String url = "http://" + mqttGatewayUrl + "/api/commands/" + mqttClientId; + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/json"); + + // 生成Bearer令牌 + String dateStr = java.time.LocalDate.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")); + String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false); + if (StringUtils.isBlank(signatureKey)) { + return new Result().error("MQTT签名密钥未配置"); + } + String tokenContent = dateStr + signatureKey; + String token = org.apache.commons.codec.digest.DigestUtils.sha256Hex(tokenContent); + headers.set("Authorization", "Bearer " + token); + + // 构建请求体 + HttpEntity requestEntity = new HttpEntity<>(command, headers); + + // 发送POST请求 + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + + // 返回响应 + return new Result().ok(response.getBody()); + } catch (Exception e) { + return new Result().error("发送指令失败: " + e.getMessage()); + } + } } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java index 9e452888..732b724b 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java @@ -188,7 +188,7 @@ public class DeviceServiceImpl extends BaseServiceImpl try { String groupId = deviceById != null && deviceById.getBoard() != null ? deviceById.getBoard() : "GID_default"; - DeviceReportRespDTO.MQTT mqtt = buildMqttConfig(macAddress, clientId, groupId); + DeviceReportRespDTO.MQTT mqtt = buildMqttConfig(macAddress, groupId); if (mqtt != null) { mqtt.setEndpoint(mqttUdpConfig); response.setMqtt(mqtt); @@ -479,11 +479,10 @@ public class DeviceServiceImpl extends BaseServiceImpl * 构建MQTT配置信息 * * @param macAddress MAC地址 - * @param clientId 客户端ID (UUID) * @param groupId 分组ID * @return MQTT配置对象 */ - private DeviceReportRespDTO.MQTT buildMqttConfig(String macAddress, String clientId, String groupId) + private DeviceReportRespDTO.MQTT buildMqttConfig(String macAddress, String groupId) throws Exception { // 从环境变量或系统参数获取签名密钥 String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false); @@ -495,8 +494,7 @@ public class DeviceServiceImpl extends BaseServiceImpl // 构建客户端ID格式:groupId@@@macAddress@@@uuid String groupIdSafeStr = groupId.replace(":", "_"); String deviceIdSafeStr = macAddress.replace(":", "_"); - String clientIdSafeStr = clientId.replace(":", "_"); - String mqttClientId = String.format("%s@@@%s@@@%s", groupIdSafeStr, deviceIdSafeStr, clientIdSafeStr); + String mqttClientId = String.format("%s@@@%s@@@%s", groupIdSafeStr, deviceIdSafeStr, deviceIdSafeStr); // 构建用户数据(包含IP等信息) Map userData = new HashMap<>(); diff --git a/main/manager-api/src/main/resources/db/changelog/202509161609.sql b/main/manager-api/src/main/resources/db/changelog/202509161609.sql new file mode 100644 index 00000000..61270e26 --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202509161609.sql @@ -0,0 +1,3 @@ +delete from `sys_params` where param_code = 'server.mqtt_manager_api'; +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) +VALUES (119, 'server.mqtt_manager_api', null, 'string', 1, 'MQTT网关管理API的地址'); diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml index 2890424d..73ea86f2 100755 --- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml @@ -345,3 +345,10 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202509080922.sql + - changeSet: + id: 202509161609 + author: fyb + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202509161609.sql \ No newline at end of file