feat(iot,ops): 区域设备关联接口返回更多设备信息,修复 N+1 和代码质量问题

- IotDeviceSimpleRespDTO 新增 nickname、serialNumber、state、deviceType 字段
- IotDeviceQueryApi 新增 batchGetDevices 批量查询接口
- IotDeviceQueryApiImpl 提取 toSimpleDTO 统一转换、通过产品缓存解析 productName、
  移除 blanket try-catch 让异常正确传播、删除无用 import
- AreaDeviceRelationRespVO 新增 nickname、serialNumber、deviceState、deviceType 字段
- AreaDeviceRelationServiceImpl.listByAreaId 改为批量查询避免 N+1 RPC、
  增加 null 防护;bindDevice 改为 fail-fast 不再存脏数据
- ErrorCodeConstants 新增 IOT_SERVICE_UNAVAILABLE 错误码

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
lzh
2026-03-07 21:06:10 +08:00
parent 3bcdb4119f
commit 26c4ce07eb
6 changed files with 203 additions and 133 deletions

View File

@@ -2,9 +2,10 @@ package com.viewsh.module.iot.api.device;
import com.viewsh.framework.common.pojo.CommonResult;
import com.viewsh.module.iot.api.device.dto.IotDeviceSimpleRespDTO;
import com.viewsh.module.iot.controller.admin.device.vo.device.IotDeviceRespVO;
import com.viewsh.module.iot.dal.dataobject.device.IotDeviceDO;
import com.viewsh.module.iot.dal.dataobject.product.IotProductDO;
import com.viewsh.module.iot.service.device.IotDeviceService;
import com.viewsh.module.iot.service.product.IotProductService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -14,8 +15,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import static com.viewsh.framework.common.pojo.CommonResult.success;
import static com.viewsh.module.iot.api.device.IotDeviceQueryApi.PREFIX;
@@ -36,55 +37,74 @@ public class IotDeviceQueryApiImpl implements IotDeviceQueryApi {
@Resource
private IotDeviceService deviceService;
@Resource
private IotProductService productService;
@Override
@GetMapping(PREFIX + "/simple-list")
@Operation(summary = "获取设备精简列表(按类型/产品筛选)")
public CommonResult<List<IotDeviceSimpleRespDTO>> getDeviceSimpleList(
@RequestParam(value = "deviceType", required = false) Integer deviceType,
@RequestParam(value = "productId", required = false) Long productId) {
try {
List<IotDeviceDO> list = deviceService.getDeviceListByCondition(deviceType, productId);
List<IotDeviceSimpleRespDTO> result = list.stream()
.map(device -> {
IotDeviceSimpleRespDTO dto = new IotDeviceSimpleRespDTO();
dto.setId(device.getId());
dto.setDeviceName(device.getDeviceName());
dto.setProductId(device.getProductId());
dto.setProductKey(device.getProductKey());
// TODO: 从产品服务获取产品名称
dto.setProductName("产品_" + device.getProductKey());
return dto;
})
.collect(Collectors.toList());
return success(result);
} catch (Exception e) {
log.error("[getDeviceSimpleList] 查询设备列表失败: deviceType={}, productId={}", deviceType, productId, e);
return success(List.of());
}
List<IotDeviceDO> list = deviceService.getDeviceListByCondition(deviceType, productId);
List<IotDeviceSimpleRespDTO> result = list.stream()
.map(this::toSimpleDTO)
.toList();
return success(result);
}
@Override
@GetMapping(PREFIX + "/get")
@Operation(summary = "获取设备详情")
public CommonResult<IotDeviceSimpleRespDTO> getDevice(@RequestParam("id") Long id) {
try {
IotDeviceDO device = deviceService.getDevice(id);
if (device == null) {
return success(null);
}
IotDeviceSimpleRespDTO dto = new IotDeviceSimpleRespDTO();
dto.setId(device.getId());
dto.setDeviceName(device.getDeviceName());
dto.setProductId(device.getProductId());
dto.setProductKey(device.getProductKey());
dto.setProductName("产品_" + device.getProductKey());
return success(dto);
} catch (Exception e) {
log.error("[getDevice] 查询设备详情失败: id={}", id, e);
IotDeviceDO device = deviceService.getDevice(id);
if (device == null) {
return success(null);
}
return success(toSimpleDTO(device));
}
@Override
@GetMapping(PREFIX + "/batch-get")
@Operation(summary = "批量获取设备详情")
public CommonResult<List<IotDeviceSimpleRespDTO>> batchGetDevices(
@RequestParam("ids") Collection<Long> ids) {
if (ids == null || ids.isEmpty()) {
return success(List.of());
}
List<IotDeviceDO> devices = deviceService.getDeviceList(ids);
List<IotDeviceSimpleRespDTO> result = devices.stream()
.map(this::toSimpleDTO)
.toList();
return success(result);
}
private IotDeviceSimpleRespDTO toSimpleDTO(IotDeviceDO device) {
IotDeviceSimpleRespDTO dto = new IotDeviceSimpleRespDTO();
dto.setId(device.getId());
dto.setDeviceName(device.getDeviceName());
dto.setProductId(device.getProductId());
dto.setProductKey(device.getProductKey());
dto.setNickname(device.getNickname());
dto.setSerialNumber(device.getSerialNumber());
dto.setState(device.getState());
dto.setDeviceType(device.getDeviceType());
// 从产品缓存获取产品名称
dto.setProductName(resolveProductName(device.getProductId()));
return dto;
}
private String resolveProductName(Long productId) {
if (productId == null) {
return null;
}
try {
IotProductDO product = productService.getProductFromCache(productId);
return product != null ? product.getName() : null;
} catch (Exception e) {
log.warn("[resolveProductName] 获取产品名称失败: productId={}, error={}", productId, e.getMessage());
return null;
}
}
}