Commit dd4027239e9f00917f4125509c38a17fe3aa9cd0

Authored by YunaiV
1 parent d783890b

feat:【IoT 物联网】新增设备序列号唯一性校验,添加序列号查询方法

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
@@ -81,6 +81,10 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> { @@ -81,6 +81,10 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
81 .in(IotDeviceDO::getDeviceName, deviceNames)); 81 .in(IotDeviceDO::getDeviceName, deviceNames));
82 } 82 }
83 83
  84 + default IotDeviceDO selectBySerialNumber(String serialNumber) {
  85 + return selectOne(IotDeviceDO::getSerialNumber, serialNumber);
  86 + }
  87 +
84 /** 88 /**
85 * 查询指定产品下的设备数量 89 * 查询指定产品下的设备数量
86 * 90 *
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -32,6 +32,7 @@ public interface ErrorCodeConstants { @@ -32,6 +32,7 @@ public interface ErrorCodeConstants {
32 ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备"); 32 ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备");
33 ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!"); 33 ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!");
34 ErrorCode DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL = new ErrorCode(1_050_003_007, "下行设备消息失败,原因:设备未连接网关"); 34 ErrorCode DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL = new ErrorCode(1_050_003_007, "下行设备消息失败,原因:设备未连接网关");
  35 + ErrorCode DEVICE_SERIAL_NUMBER_EXISTS = new ErrorCode(1_050_003_008, "设备序列号已存在,序列号必须全局唯一");
35 36
36 // ========== 产品分类 1-050-004-000 ========== 37 // ========== 产品分类 1-050-004-000 ==========
37 ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在"); 38 ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在");
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
@@ -3,10 +3,9 @@ package cn.iocoder.yudao.module.iot.service.device; @@ -3,10 +3,9 @@ package cn.iocoder.yudao.module.iot.service.device;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; 4 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
5 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; 5 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
6 -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;  
7 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; 6 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
8 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
9 -import jakarta.validation.constraints.NotEmpty;  
10 9
11 import javax.annotation.Nullable; 10 import javax.annotation.Nullable;
12 import java.time.LocalDateTime; 11 import java.time.LocalDateTime;
@@ -31,18 +30,6 @@ public interface IotDeviceService { @@ -31,18 +30,6 @@ public interface IotDeviceService {
31 Long createDevice(@Valid IotDeviceSaveReqVO createReqVO); 30 Long createDevice(@Valid IotDeviceSaveReqVO createReqVO);
32 31
33 /** 32 /**
34 - * 【设备注册】创建设备  
35 - *  
36 - * @param productKey 产品标识  
37 - * @param deviceName 设备名称  
38 - * @param gatewayId 网关设备 ID  
39 - * @return 设备  
40 - */  
41 - IotDeviceDO createDevice(@NotEmpty(message = "产品标识不能为空") String productKey,  
42 - @NotEmpty(message = "设备名称不能为空") String deviceName,  
43 - Long gatewayId);  
44 -  
45 - /**  
46 * 更新设备 33 * 更新设备
47 * 34 *
48 * @param updateReqVO 更新信息 35 * @param updateReqVO 更新信息
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
@@ -73,6 +73,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -73,6 +73,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
73 createReqVO.getGatewayId(), product); 73 createReqVO.getGatewayId(), product);
74 // 1.3 校验分组存在 74 // 1.3 校验分组存在
75 deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds()); 75 deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds());
  76 + // 1.4 校验设备序列号全局唯一
  77 + validateSerialNumberUnique(createReqVO.getSerialNumber(), null);
76 78
77 // 2. 插入到数据库 79 // 2. 插入到数据库
78 IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class); 80 IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class);
@@ -81,34 +83,14 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -81,34 +83,14 @@ public class IotDeviceServiceImpl implements IotDeviceService {
81 return device.getId(); 83 return device.getId();
82 } 84 }
83 85
84 - @Override  
85 - public IotDeviceDO createDevice(String productKey, String deviceName, Long gatewayId) {  
86 - // 1.1 校验产品是否存在  
87 - IotProductDO product = TenantUtils.executeIgnore(() -> productService.getProductByProductKey(productKey));  
88 - if (product == null) {  
89 - throw exception(PRODUCT_NOT_EXISTS);  
90 - }  
91 - return TenantUtils.execute(product.getTenantId(), () -> {  
92 - // 1.2 校验设备名称在同一产品下是否唯一  
93 - validateCreateDeviceParam(productKey, deviceName, gatewayId, product);  
94 -  
95 - // 2. 插入到数据库  
96 - IotDeviceDO device = new IotDeviceDO().setDeviceName(deviceName).setGatewayId(gatewayId);  
97 - initDevice(device, product);  
98 - deviceMapper.insert(device);  
99 - return device;  
100 - });  
101 - }  
102 -  
103 private void validateCreateDeviceParam(String productKey, String deviceName, 86 private void validateCreateDeviceParam(String productKey, String deviceName,
104 Long gatewayId, IotProductDO product) { 87 Long gatewayId, IotProductDO product) {
  88 + // 校验设备名称在同一产品下是否唯一
105 TenantUtils.executeIgnore(() -> { 89 TenantUtils.executeIgnore(() -> {
106 - // 校验设备名称在同一产品下是否唯一  
107 if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) { 90 if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) {
108 throw exception(DEVICE_NAME_EXISTS); 91 throw exception(DEVICE_NAME_EXISTS);
109 } 92 }
110 }); 93 });
111 -  
112 // 校验父设备是否为合法网关 94 // 校验父设备是否为合法网关
113 if (IotProductDeviceTypeEnum.isGatewaySub(product.getDeviceType()) 95 if (IotProductDeviceTypeEnum.isGatewaySub(product.getDeviceType())
114 && gatewayId != null) { 96 && gatewayId != null) {
@@ -116,6 +98,22 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -116,6 +98,22 @@ public class IotDeviceServiceImpl implements IotDeviceService {
116 } 98 }
117 } 99 }
118 100
  101 + /**
  102 + * 校验设备序列号全局唯一性
  103 + *
  104 + * @param serialNumber 设备序列号
  105 + * @param excludeId 排除的设备ID(用于更新时排除自身)
  106 + */
  107 + private void validateSerialNumberUnique(String serialNumber, Long excludeId) {
  108 + if (StrUtil.isBlank(serialNumber)) {
  109 + return;
  110 + }
  111 + IotDeviceDO existDevice = deviceMapper.selectBySerialNumber(serialNumber);
  112 + if (existDevice != null && ObjUtil.notEqual(existDevice.getId(), excludeId)) {
  113 + throw exception(DEVICE_SERIAL_NUMBER_EXISTS);
  114 + }
  115 + }
  116 +
119 private void initDevice(IotDeviceDO device, IotProductDO product) { 117 private void initDevice(IotDeviceDO device, IotProductDO product) {
120 device.setProductId(product.getId()).setProductKey(product.getProductKey()) 118 device.setProductId(product.getId()).setProductKey(product.getProductKey())
121 .setDeviceType(product.getDeviceType()); 119 .setDeviceType(product.getDeviceType());
@@ -137,6 +135,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -137,6 +135,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
137 } 135 }
138 // 1.3 校验分组存在 136 // 1.3 校验分组存在
139 deviceGroupService.validateDeviceGroupExists(updateReqVO.getGroupIds()); 137 deviceGroupService.validateDeviceGroupExists(updateReqVO.getGroupIds());
  138 + // 1.4 校验设备序列号全局唯一
  139 + validateSerialNumberUnique(updateReqVO.getSerialNumber(), updateReqVO.getId());
140 140
141 // 2. 更新到数据库 141 // 2. 更新到数据库
142 IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); 142 IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
@@ -417,6 +417,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -417,6 +417,7 @@ public class IotDeviceServiceImpl implements IotDeviceService {
417 devices.forEach(this::deleteDeviceCache); 417 devices.forEach(this::deleteDeviceCache);
418 } 418 }
419 419
  420 + @SuppressWarnings("unused")
420 @Caching(evict = { 421 @Caching(evict = {
421 @CacheEvict(value = RedisKeyConstants.DEVICE, key = "#device.id"), 422 @CacheEvict(value = RedisKeyConstants.DEVICE, key = "#device.id"),
422 @CacheEvict(value = RedisKeyConstants.DEVICE, key = "#device.productKey + '_' + #device.deviceName") 423 @CacheEvict(value = RedisKeyConstants.DEVICE, key = "#device.productKey + '_' + #device.deviceName")