Commit dd4027239e9f00917f4125509c38a17fe3aa9cd0
1 parent
d783890b
feat:【IoT 物联网】新增设备序列号唯一性校验,添加序列号查询方法
Showing
4 changed files
with
28 additions
and
35 deletions
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") |