Commit 2a04bdc3fe8998c02ea12477deeb251923e0083c

Authored by YunaiV
1 parent 956418d3

feat:【IoT 物联网】完整实现“数据流转”功能(后台管理)

Showing 18 changed files with 216 additions and 25 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
... ... @@ -58,7 +58,8 @@ public interface ErrorCodeConstants {
58 58 ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在");
59 59  
60 60 // ========== IoT 数据流转目的 1-050-011-000 ==========
61   - ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_011_000, "数据桥梁不存在");
  61 + ErrorCode DATA_SINK_NOT_EXISTS = new ErrorCode(1_050_011_000, "数据桥梁不存在");
  62 + ErrorCode DATA_SINK_DELETE_FAIL_USED_BY_RULE = new ErrorCode(1_050_011_001, "数据流转目的正在被数据流转规则使用,无法删除");
62 63  
63 64 // ========== IoT 场景联动 1-050-012-000 ==========
64 65 ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_012_000, "场景联动不存在");
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
... ... @@ -9,7 +9,6 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
9 9 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
10 10 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
11 11 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
12   -import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService;
13 12 import io.swagger.v3.oas.annotations.Operation;
14 13 import io.swagger.v3.oas.annotations.Parameter;
15 14 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -38,8 +37,6 @@ public class IotDeviceController {
38 37  
39 38 @Resource
40 39 private IotDeviceService deviceService;
41   - @Resource
42   - private IotDeviceMessageService deviceMessageService;
43 40  
44 41 @PostMapping("/create")
45 42 @Operation(summary = "创建设备")
... ... @@ -125,11 +122,12 @@ public class IotDeviceController {
125 122 @GetMapping("/simple-list")
126 123 @Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项")
127 124 @Parameter(name = "deviceType", description = "设备类型", example = "1")
128   - public CommonResult<List<IotDeviceRespVO>> getSimpleDeviceList(
  125 + public CommonResult<List<IotDeviceRespVO>> getDeviceSimpleList(
129 126 @RequestParam(value = "deviceType", required = false) Integer deviceType) {
130 127 List<IotDeviceDO> list = deviceService.getDeviceListByDeviceType(deviceType);
131   - return success(convertList(list, device -> // 只返回 id、name 字段
132   - new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName())));
  128 + return success(convertList(list, device -> // 只返回 id、name、productId 字段
  129 + new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName())
  130 + .setProductId(device.getProductId())));
133 131 }
134 132  
135 133 @PostMapping("/import")
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java
... ... @@ -143,7 +143,7 @@ public class IotProductController {
143 143  
144 144 @GetMapping("/simple-list")
145 145 @Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项")
146   - public CommonResult<List<IotProductRespVO>> getSimpleProductList() {
  146 + public CommonResult<List<IotProductRespVO>> getProductSimpleList() {
147 147 List<IotProductDO> list = productService.getProductList();
148 148 return success(convertList(list, product -> // 只返回 id、name 字段
149 149 new IotProductRespVO().setId(product.getId()).setName(product.getName())
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRulePageReqVO.java
... ... @@ -13,10 +13,10 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
13 13 @Data
14 14 public class IotDataRulePageReqVO extends PageParam {
15 15  
16   - @Schema(description = "场景名称", example = "芋艿")
  16 + @Schema(description = "数据流转规则名称", example = "芋艿")
17 17 private String name;
18 18  
19   - @Schema(description = "场景状态", example = "1")
  19 + @Schema(description = "数据流转规则状态", example = "1")
20 20 private Integer status;
21 21  
22 22 @Schema(description = "创建时间")
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleRespVO.java
... ... @@ -11,16 +11,16 @@ import java.util.List;
11 11 @Data
12 12 public class IotDataRuleRespVO {
13 13  
14   - @Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8540")
  14 + @Schema(description = "数据流转规则编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8540")
15 15 private Long id;
16 16  
17   - @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
  17 + @Schema(description = "数据流转规则名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
18 18 private String name;
19 19  
20   - @Schema(description = "场景描述", example = "你猜")
  20 + @Schema(description = "数据流转规则描述", example = "你猜")
21 21 private String description;
22 22  
23   - @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  23 + @Schema(description = "数据流转规则状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
24 24 private Integer status;
25 25  
26 26 @Schema(description = "数据源配置数组", requiredMode = Schema.RequiredMode.REQUIRED)
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleSaveReqVO.java
... ... @@ -14,18 +14,18 @@ import java.util.List;
14 14 @Data
15 15 public class IotDataRuleSaveReqVO {
16 16  
17   - @Schema(description = "场景编号", example = "8540")
  17 + @Schema(description = "数据流转规则编号", example = "8540")
18 18 private Long id;
19 19  
20   - @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
21   - @NotEmpty(message = "场景名称不能为空")
  20 + @Schema(description = "数据流转规则名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
  21 + @NotEmpty(message = "数据流转规则名称不能为空")
22 22 private String name;
23 23  
24   - @Schema(description = "场景描述", example = "你猜")
  24 + @Schema(description = "数据流转规则描述", example = "你猜")
25 25 private String description;
26 26  
27   - @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
28   - @NotNull(message = "场景状态不能为空")
  27 + @Schema(description = "数据流转规则状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  28 + @NotNull(message = "数据流转规则状态不能为空")
29 29 @InEnum(CommonStatusEnum.class)
30 30 private Integer status;
31 31  
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
... ... @@ -6,9 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
6 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
7 7 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO;
8 8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  9 +import jakarta.annotation.Nullable;
9 10 import org.apache.ibatis.annotations.Mapper;
10 11  
11   -import javax.annotation.Nullable;
12 12 import java.time.LocalDateTime;
13 13 import java.util.Collection;
14 14 import java.util.List;
... ... @@ -50,8 +50,9 @@ public interface IotDeviceMapper extends BaseMapperX&lt;IotDeviceDO&gt; {
50 50 return selectCount(IotDeviceDO::getProductId, productId);
51 51 }
52 52  
53   - default List<IotDeviceDO> selectListByDeviceType(Integer deviceType) {
54   - return selectList(IotDeviceDO::getDeviceType, deviceType);
  53 + default List<IotDeviceDO> selectListByDeviceType(@Nullable Integer deviceType) {
  54 + return selectList(new LambdaQueryWrapperX<IotDeviceDO>()
  55 + .geIfPresent(IotDeviceDO::getDeviceType, deviceType));
55 56 }
56 57  
57 58 default List<IotDeviceDO> selectListByState(Integer state) {
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java
... ... @@ -3,10 +3,13 @@ package cn.iocoder.yudao.module.iot.dal.mysql.rule;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
6 7 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO;
7 8 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO;
8 9 import org.apache.ibatis.annotations.Mapper;
9 10  
  11 +import java.util.List;
  12 +
10 13 /**
11 14 * IoT 数据流转规则 Mapper
12 15 *
... ... @@ -23,4 +26,9 @@ public interface IotDataRuleMapper extends BaseMapperX&lt;IotDataRuleDO&gt; {
23 26 .orderByDesc(IotDataRuleDO::getId));
24 27 }
25 28  
  29 + default List<IotDataRuleDO> selectListBySinkId(Long sinkId) {
  30 + return selectList(new LambdaQueryWrapperX<IotDataRuleDO>()
  31 + .apply(MyBatisUtils.findInSet("sink_ids", sinkId)));
  32 + }
  33 +
26 34 }
27 35 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
... ... @@ -13,6 +13,7 @@ import java.time.LocalDateTime;
13 13 import java.util.Collection;
14 14 import java.util.List;
15 15 import java.util.Map;
  16 +import java.util.Set;
16 17  
17 18 /**
18 19 * IoT 设备 Service 接口
... ... @@ -255,4 +256,11 @@ public interface IotDeviceService {
255 256 */
256 257 boolean authDevice(@Valid IotDeviceAuthReqDTO authReqDTO);
257 258  
  259 + /**
  260 + * 校验设备是否存在
  261 + *
  262 + * @param ids 设备编号数组
  263 + */
  264 + void validateDevicesExist(Set<Long> ids);
  265 +
258 266 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
... ... @@ -483,6 +483,17 @@ public class IotDeviceServiceImpl implements IotDeviceService {
483 483 return true;
484 484 }
485 485  
  486 + @Override
  487 + public void validateDevicesExist(Set<Long> ids) {
  488 + if (CollUtil.isEmpty(ids)) {
  489 + return;
  490 + }
  491 + List<IotDeviceDO> deviceIds = deviceMapper.selectByIds(ids);
  492 + if (deviceIds.size() != ids.size()) {
  493 + throw exception(DEVICE_NOT_EXISTS);
  494 + }
  495 + }
  496 +
486 497 private IotDeviceServiceImpl getSelf() {
487 498 return SpringUtil.getBean(getClass());
488 499 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java
... ... @@ -8,6 +8,7 @@ import jakarta.validation.Valid;
8 8  
9 9 import javax.annotation.Nullable;
10 10 import java.time.LocalDateTime;
  11 +import java.util.Collection;
11 12 import java.util.List;
12 13  
13 14 /**
... ... @@ -112,5 +113,11 @@ public interface IotProductService {
112 113 */
113 114 Long getProductCount(@Nullable LocalDateTime createTime);
114 115  
  116 + /**
  117 + * 批量校验产品存在
  118 + *
  119 + * @param ids 产品编号集合
  120 + */
  121 + void validateProductsExist(Collection<Long> ids);
115 122  
116 123 }
117 124 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.service.product;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 6 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
... ... @@ -20,6 +21,7 @@ import org.springframework.stereotype.Service;
20 21 import org.springframework.validation.annotation.Validated;
21 22  
22 23 import java.time.LocalDateTime;
  24 +import java.util.Collection;
23 25 import java.util.List;
24 26 import java.util.Objects;
25 27  
... ... @@ -157,4 +159,15 @@ public class IotProductServiceImpl implements IotProductService {
157 159 return productMapper.selectCountByCreateTime(createTime);
158 160 }
159 161  
  162 + @Override
  163 + public void validateProductsExist(Collection<Long> ids) {
  164 + if (CollUtil.isEmpty(ids)) {
  165 + return;
  166 + }
  167 + List<IotProductDO> products = productMapper.selectByIds(ids);
  168 + if (products.size() != ids.size()) {
  169 + throw exception(PRODUCT_NOT_EXISTS);
  170 + }
  171 + }
  172 +
160 173 }
161 174 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java
1 1 package cn.iocoder.yudao.module.iot.service.rule.data;
2 2  
  3 +import java.util.List;
  4 +
3 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 6 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO;
5 7 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO;
... ... @@ -51,4 +53,12 @@ public interface IotDataRuleService {
51 53 */
52 54 PageResult<IotDataRuleDO> getDataRulePage(IotDataRulePageReqVO pageReqVO);
53 55  
  56 + /**
  57 + * 根据数据目的编号,获得数据流转规则列表
  58 + *
  59 + * @param sinkId 数据目的编号
  60 + * @return 是否被使用
  61 + */
  62 + List<IotDataRuleDO> getDataRuleBySinkId(Long sinkId);
  63 +
54 64 }
55 65 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.service.rule.data;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjUtil;
  5 +import cn.hutool.core.util.StrUtil;
3 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 8 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO;
6 9 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO;
  10 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
7 11 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO;
8 12 import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataRuleMapper;
  13 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  14 +import cn.iocoder.yudao.module.iot.service.product.IotProductService;
  15 +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
9 16 import jakarta.annotation.Resource;
10 17 import org.springframework.stereotype.Service;
11 18 import org.springframework.validation.annotation.Validated;
12 19  
  20 +import java.util.*;
  21 +
13 22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  23 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
14 24 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_RULE_NOT_EXISTS;
15 25  
16 26 /**
... ... @@ -25,8 +35,20 @@ public class IotDataRuleServiceImpl implements IotDataRuleService {
25 35 @Resource
26 36 private IotDataRuleMapper dataRuleMapper;
27 37  
  38 + @Resource
  39 + private IotProductService productService;
  40 + @Resource
  41 + private IotDeviceService deviceService;
  42 + @Resource
  43 + private IotThingModelService thingModelService;
  44 + @Resource
  45 + private IotDataSinkService dataSinkService;
  46 +
28 47 @Override
29 48 public Long createDataRule(IotDataRuleSaveReqVO createReqVO) {
  49 + // 校验数据源配置和数据目的
  50 + validateDataRuleConfig(createReqVO);
  51 + // 新增
30 52 IotDataRuleDO dataRule = BeanUtils.toBean(createReqVO, IotDataRuleDO.class);
31 53 dataRuleMapper.insert(dataRule);
32 54 return dataRule.getId();
... ... @@ -36,6 +58,9 @@ public class IotDataRuleServiceImpl implements IotDataRuleService {
36 58 public void updateDataRule(IotDataRuleSaveReqVO updateReqVO) {
37 59 // 校验存在
38 60 validateDataRuleExists(updateReqVO.getId());
  61 + // 校验数据源配置和数据目的
  62 + validateDataRuleConfig(updateReqVO);
  63 +
39 64 // 更新
40 65 IotDataRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotDataRuleDO.class);
41 66 dataRuleMapper.updateById(updateObj);
... ... @@ -55,6 +80,55 @@ public class IotDataRuleServiceImpl implements IotDataRuleService {
55 80 }
56 81 }
57 82  
  83 + /**
  84 + * 校验数据流转规则配置
  85 + *
  86 + * @param reqVO 数据流转规则保存请求VO
  87 + */
  88 + private void validateDataRuleConfig(IotDataRuleSaveReqVO reqVO) {
  89 + // 1. 校验数据源配置
  90 + validateSourceConfigs(reqVO.getSourceConfigs());
  91 + // 2. 校验数据目的
  92 + dataSinkService.validateDataSinksExist(reqVO.getSinkIds());
  93 + }
  94 +
  95 + /**
  96 + * 校验数据源配置
  97 + *
  98 + * @param sourceConfigs 数据源配置列表
  99 + */
  100 + private void validateSourceConfigs(List<IotDataRuleDO.SourceConfig> sourceConfigs) {
  101 + // 1. 校验产品
  102 + productService.validateProductsExist(
  103 + convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getProductId));
  104 +
  105 + // 2. 校验设备
  106 + deviceService.validateDevicesExist(convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getDeviceId,
  107 + config -> ObjUtil.notEqual(config.getDeviceId(), IotDeviceDO.DEVICE_ID_ALL)));
  108 +
  109 + // 3. 校验物模型存在
  110 + validateThingModelsExist(sourceConfigs);
  111 + }
  112 +
  113 + /**
  114 + * 校验物模型存在
  115 + *
  116 + * @param sourceConfigs 数据源配置列表
  117 + */
  118 + private void validateThingModelsExist(List<IotDataRuleDO.SourceConfig> sourceConfigs) {
  119 + Map<Long, Set<String>> productIdToIdentifiers = new HashMap<>();
  120 + for (IotDataRuleDO.SourceConfig config : sourceConfigs) {
  121 + if (StrUtil.isEmpty(config.getIdentifier())) {
  122 + continue;
  123 + }
  124 + productIdToIdentifiers.computeIfAbsent(config.getProductId(),
  125 + productId -> new HashSet<>()).add(config.getIdentifier());
  126 + }
  127 + for (Map.Entry<Long, Set<String>> entry : productIdToIdentifiers.entrySet()) {
  128 + thingModelService.validateThingModelsExist(entry.getKey(), entry.getValue());
  129 + }
  130 + }
  131 +
58 132 @Override
59 133 public IotDataRuleDO getDataRule(Long id) {
60 134 return dataRuleMapper.selectById(id);
... ... @@ -65,4 +139,9 @@ public class IotDataRuleServiceImpl implements IotDataRuleService {
65 139 return dataRuleMapper.selectPage(pageReqVO);
66 140 }
67 141  
  142 + @Override
  143 + public List<IotDataRuleDO> getDataRuleBySinkId(Long sinkId) {
  144 + return dataRuleMapper.selectListBySinkId(sinkId);
  145 + }
  146 +
68 147 }
69 148 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSin
6 6 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO;
7 7 import jakarta.validation.Valid;
8 8  
  9 +import java.util.Collection;
9 10 import java.util.List;
10 11  
11 12 /**
... ... @@ -61,4 +62,11 @@ public interface IotDataSinkService {
61 62 */
62 63 List<IotDataSinkDO> getDataSinkListByStatus(Integer status);
63 64  
  65 + /**
  66 + * 批量校验数据目的存在
  67 + *
  68 + * @param ids 数据目的编号集合
  69 + */
  70 + void validateDataSinksExist(Collection<Long> ids);
  71 +
64 72 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.service.rule.data;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 6 import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkPageReqVO;
... ... @@ -7,13 +8,16 @@ import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSin
7 8 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO;
8 9 import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataSinkMapper;
9 10 import jakarta.annotation.Resource;
  11 +import org.springframework.context.annotation.Lazy;
10 12 import org.springframework.stereotype.Service;
11 13 import org.springframework.validation.annotation.Validated;
12 14  
  15 +import java.util.Collection;
13 16 import java.util.List;
14 17  
15 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
16   -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_BRIDGE_NOT_EXISTS;
  19 +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_SINK_NOT_EXISTS;
  20 +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_SINK_DELETE_FAIL_USED_BY_RULE;
17 21  
18 22 /**
19 23 * IoT 数据流转目的 Service 实现类
... ... @@ -27,6 +31,10 @@ public class IotDataSinkServiceImpl implements IotDataSinkService {
27 31 @Resource
28 32 private IotDataSinkMapper dataSinkMapper;
29 33  
  34 + @Resource
  35 + @Lazy // 延迟,避免循环依赖报错
  36 + private IotDataRuleService dataRuleService;
  37 +
30 38 @Override
31 39 public Long createDataSink(IotDataSinkSaveReqVO createReqVO) {
32 40 IotDataSinkDO dataBridge = BeanUtils.toBean(createReqVO, IotDataSinkDO.class);
... ... @@ -47,13 +55,17 @@ public class IotDataSinkServiceImpl implements IotDataSinkService {
47 55 public void deleteDataSink(Long id) {
48 56 // 校验存在
49 57 validateDataBridgeExists(id);
  58 + // 校验是否被数据流转规则使用
  59 + if (CollUtil.isNotEmpty(dataRuleService.getDataRuleBySinkId(id))) {
  60 + throw exception(DATA_SINK_DELETE_FAIL_USED_BY_RULE);
  61 + }
50 62 // 删除
51 63 dataSinkMapper.deleteById(id);
52 64 }
53 65  
54 66 private void validateDataBridgeExists(Long id) {
55 67 if (dataSinkMapper.selectById(id) == null) {
56   - throw exception(DATA_BRIDGE_NOT_EXISTS);
  68 + throw exception(DATA_SINK_NOT_EXISTS);
57 69 }
58 70 }
59 71  
... ... @@ -72,4 +84,15 @@ public class IotDataSinkServiceImpl implements IotDataSinkService {
72 84 return dataSinkMapper.selectListByStatus(status);
73 85 }
74 86  
  87 + @Override
  88 + public void validateDataSinksExist(Collection<Long> ids) {
  89 + if (CollUtil.isEmpty(ids)) {
  90 + return;
  91 + }
  92 + List<IotDataSinkDO> sinks = dataSinkMapper.selectByIds(ids);
  93 + if (sinks.size() != ids.size()) {
  94 + throw exception(DATA_SINK_NOT_EXISTS);
  95 + }
  96 + }
  97 +
75 98 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java
... ... @@ -9,6 +9,7 @@ import jakarta.validation.Valid;
9 9  
10 10 import java.util.Collection;
11 11 import java.util.List;
  12 +import java.util.Set;
12 13  
13 14 /**
14 15 * IoT 产品物模型 Service 接口
... ... @@ -99,4 +100,12 @@ public interface IotThingModelService {
99 100 */
100 101 List<IotThingModelDO> getThingModelList(IotThingModelListReqVO reqVO);
101 102  
  103 + /**
  104 + * 批量校验物模型存在
  105 + *
  106 + * @param productId 产品编号
  107 + * @param identifiers 标识符集合
  108 + */
  109 + void validateThingModelsExist(Long productId, Set<String> identifiers);
  110 +
102 111 }
103 112 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java
... ... @@ -158,6 +158,21 @@ public class IotThingModelServiceImpl implements IotThingModelService {
158 158 return thingModelMapper.selectList(reqVO);
159 159 }
160 160  
  161 + @Override
  162 + public void validateThingModelsExist(Long productId, Set<String> identifiers) {
  163 + if (CollUtil.isEmpty(identifiers)) {
  164 + return;
  165 + }
  166 + List<IotThingModelDO> thingModels = thingModelMapper.selectListByProductIdAndIdentifiers(
  167 + productId, identifiers);
  168 + Set<String> foundIdentifiers = convertSet(thingModels, IotThingModelDO::getIdentifier);
  169 + for (String identifier : identifiers) {
  170 + if (!foundIdentifiers.contains(identifier)) {
  171 + throw exception(THING_MODEL_NOT_EXISTS);
  172 + }
  173 + }
  174 + }
  175 +
161 176 /**
162 177 * 校验功能是否存在
163 178 *
... ...