Commit 2a04bdc3fe8998c02ea12477deeb251923e0083c
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,7 +58,8 @@ public interface ErrorCodeConstants { | ||
| 58 | ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在"); | 58 | ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在"); |
| 59 | 59 | ||
| 60 | // ========== IoT 数据流转目的 1-050-011-000 ========== | 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 | // ========== IoT 场景联动 1-050-012-000 ========== | 64 | // ========== IoT 场景联动 1-050-012-000 ========== |
| 64 | ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_012_000, "场景联动不存在"); | 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,7 +9,6 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | ||
| 9 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; | 9 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; |
| 10 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | 10 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 11 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | 11 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 12 | -import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; | ||
| 13 | import io.swagger.v3.oas.annotations.Operation; | 12 | import io.swagger.v3.oas.annotations.Operation; |
| 14 | import io.swagger.v3.oas.annotations.Parameter; | 13 | import io.swagger.v3.oas.annotations.Parameter; |
| 15 | import io.swagger.v3.oas.annotations.tags.Tag; | 14 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -38,8 +37,6 @@ public class IotDeviceController { | @@ -38,8 +37,6 @@ public class IotDeviceController { | ||
| 38 | 37 | ||
| 39 | @Resource | 38 | @Resource |
| 40 | private IotDeviceService deviceService; | 39 | private IotDeviceService deviceService; |
| 41 | - @Resource | ||
| 42 | - private IotDeviceMessageService deviceMessageService; | ||
| 43 | 40 | ||
| 44 | @PostMapping("/create") | 41 | @PostMapping("/create") |
| 45 | @Operation(summary = "创建设备") | 42 | @Operation(summary = "创建设备") |
| @@ -125,11 +122,12 @@ public class IotDeviceController { | @@ -125,11 +122,12 @@ public class IotDeviceController { | ||
| 125 | @GetMapping("/simple-list") | 122 | @GetMapping("/simple-list") |
| 126 | @Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项") | 123 | @Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项") |
| 127 | @Parameter(name = "deviceType", description = "设备类型", example = "1") | 124 | @Parameter(name = "deviceType", description = "设备类型", example = "1") |
| 128 | - public CommonResult<List<IotDeviceRespVO>> getSimpleDeviceList( | 125 | + public CommonResult<List<IotDeviceRespVO>> getDeviceSimpleList( |
| 129 | @RequestParam(value = "deviceType", required = false) Integer deviceType) { | 126 | @RequestParam(value = "deviceType", required = false) Integer deviceType) { |
| 130 | List<IotDeviceDO> list = deviceService.getDeviceListByDeviceType(deviceType); | 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 | @PostMapping("/import") | 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,7 +143,7 @@ public class IotProductController { | ||
| 143 | 143 | ||
| 144 | @GetMapping("/simple-list") | 144 | @GetMapping("/simple-list") |
| 145 | @Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项") | 145 | @Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项") |
| 146 | - public CommonResult<List<IotProductRespVO>> getSimpleProductList() { | 146 | + public CommonResult<List<IotProductRespVO>> getProductSimpleList() { |
| 147 | List<IotProductDO> list = productService.getProductList(); | 147 | List<IotProductDO> list = productService.getProductList(); |
| 148 | return success(convertList(list, product -> // 只返回 id、name 字段 | 148 | return success(convertList(list, product -> // 只返回 id、name 字段 |
| 149 | new IotProductRespVO().setId(product.getId()).setName(product.getName()) | 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,10 +13,10 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ | ||
| 13 | @Data | 13 | @Data |
| 14 | public class IotDataRulePageReqVO extends PageParam { | 14 | public class IotDataRulePageReqVO extends PageParam { |
| 15 | 15 | ||
| 16 | - @Schema(description = "场景名称", example = "芋艿") | 16 | + @Schema(description = "数据流转规则名称", example = "芋艿") |
| 17 | private String name; | 17 | private String name; |
| 18 | 18 | ||
| 19 | - @Schema(description = "场景状态", example = "1") | 19 | + @Schema(description = "数据流转规则状态", example = "1") |
| 20 | private Integer status; | 20 | private Integer status; |
| 21 | 21 | ||
| 22 | @Schema(description = "创建时间") | 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,16 +11,16 @@ import java.util.List; | ||
| 11 | @Data | 11 | @Data |
| 12 | public class IotDataRuleRespVO { | 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 | private Long id; | 15 | private Long id; |
| 16 | 16 | ||
| 17 | - @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") | 17 | + @Schema(description = "数据流转规则名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") |
| 18 | private String name; | 18 | private String name; |
| 19 | 19 | ||
| 20 | - @Schema(description = "场景描述", example = "你猜") | 20 | + @Schema(description = "数据流转规则描述", example = "你猜") |
| 21 | private String description; | 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 | private Integer status; | 24 | private Integer status; |
| 25 | 25 | ||
| 26 | @Schema(description = "数据源配置数组", requiredMode = Schema.RequiredMode.REQUIRED) | 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,18 +14,18 @@ import java.util.List; | ||
| 14 | @Data | 14 | @Data |
| 15 | public class IotDataRuleSaveReqVO { | 15 | public class IotDataRuleSaveReqVO { |
| 16 | 16 | ||
| 17 | - @Schema(description = "场景编号", example = "8540") | 17 | + @Schema(description = "数据流转规则编号", example = "8540") |
| 18 | private Long id; | 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 | private String name; | 22 | private String name; |
| 23 | 23 | ||
| 24 | - @Schema(description = "场景描述", example = "你猜") | 24 | + @Schema(description = "数据流转规则描述", example = "你猜") |
| 25 | private String description; | 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 | @InEnum(CommonStatusEnum.class) | 29 | @InEnum(CommonStatusEnum.class) |
| 30 | private Integer status; | 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,9 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 6 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 6 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 7 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; | 7 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; |
| 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 9 | +import jakarta.annotation.Nullable; | ||
| 9 | import org.apache.ibatis.annotations.Mapper; | 10 | import org.apache.ibatis.annotations.Mapper; |
| 10 | 11 | ||
| 11 | -import javax.annotation.Nullable; | ||
| 12 | import java.time.LocalDateTime; | 12 | import java.time.LocalDateTime; |
| 13 | import java.util.Collection; | 13 | import java.util.Collection; |
| 14 | import java.util.List; | 14 | import java.util.List; |
| @@ -50,8 +50,9 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> { | @@ -50,8 +50,9 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> { | ||
| 50 | return selectCount(IotDeviceDO::getProductId, productId); | 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 | default List<IotDeviceDO> selectListByState(Integer state) { | 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,10 +3,13 @@ package cn.iocoder.yudao.module.iot.dal.mysql.rule; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; | ||
| 6 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; | 7 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; |
| 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; |
| 8 | import org.apache.ibatis.annotations.Mapper; | 9 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 10 | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 10 | /** | 13 | /** |
| 11 | * IoT 数据流转规则 Mapper | 14 | * IoT 数据流转规则 Mapper |
| 12 | * | 15 | * |
| @@ -23,4 +26,9 @@ public interface IotDataRuleMapper extends BaseMapperX<IotDataRuleDO> { | @@ -23,4 +26,9 @@ public interface IotDataRuleMapper extends BaseMapperX<IotDataRuleDO> { | ||
| 23 | .orderByDesc(IotDataRuleDO::getId)); | 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 | \ No newline at end of file | 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,6 +13,7 @@ import java.time.LocalDateTime; | ||
| 13 | import java.util.Collection; | 13 | import java.util.Collection; |
| 14 | import java.util.List; | 14 | import java.util.List; |
| 15 | import java.util.Map; | 15 | import java.util.Map; |
| 16 | +import java.util.Set; | ||
| 16 | 17 | ||
| 17 | /** | 18 | /** |
| 18 | * IoT 设备 Service 接口 | 19 | * IoT 设备 Service 接口 |
| @@ -255,4 +256,11 @@ public interface IotDeviceService { | @@ -255,4 +256,11 @@ public interface IotDeviceService { | ||
| 255 | */ | 256 | */ |
| 256 | boolean authDevice(@Valid IotDeviceAuthReqDTO authReqDTO); | 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,6 +483,17 @@ public class IotDeviceServiceImpl implements IotDeviceService { | ||
| 483 | return true; | 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 | private IotDeviceServiceImpl getSelf() { | 497 | private IotDeviceServiceImpl getSelf() { |
| 487 | return SpringUtil.getBean(getClass()); | 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,6 +8,7 @@ import jakarta.validation.Valid; | ||
| 8 | 8 | ||
| 9 | import javax.annotation.Nullable; | 9 | import javax.annotation.Nullable; |
| 10 | import java.time.LocalDateTime; | 10 | import java.time.LocalDateTime; |
| 11 | +import java.util.Collection; | ||
| 11 | import java.util.List; | 12 | import java.util.List; |
| 12 | 13 | ||
| 13 | /** | 14 | /** |
| @@ -112,5 +113,11 @@ public interface IotProductService { | @@ -112,5 +113,11 @@ public interface IotProductService { | ||
| 112 | */ | 113 | */ |
| 113 | Long getProductCount(@Nullable LocalDateTime createTime); | 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 | \ No newline at end of file | 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 | package cn.iocoder.yudao.module.iot.service.product; | 1 | package cn.iocoder.yudao.module.iot.service.product; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | 6 | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; |
| @@ -20,6 +21,7 @@ import org.springframework.stereotype.Service; | @@ -20,6 +21,7 @@ import org.springframework.stereotype.Service; | ||
| 20 | import org.springframework.validation.annotation.Validated; | 21 | import org.springframework.validation.annotation.Validated; |
| 21 | 22 | ||
| 22 | import java.time.LocalDateTime; | 23 | import java.time.LocalDateTime; |
| 24 | +import java.util.Collection; | ||
| 23 | import java.util.List; | 25 | import java.util.List; |
| 24 | import java.util.Objects; | 26 | import java.util.Objects; |
| 25 | 27 | ||
| @@ -157,4 +159,15 @@ public class IotProductServiceImpl implements IotProductService { | @@ -157,4 +159,15 @@ public class IotProductServiceImpl implements IotProductService { | ||
| 157 | return productMapper.selectCountByCreateTime(createTime); | 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 | \ No newline at end of file | 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 | package cn.iocoder.yudao.module.iot.service.rule.data; | 1 | package cn.iocoder.yudao.module.iot.service.rule.data; |
| 2 | 2 | ||
| 3 | +import java.util.List; | ||
| 4 | + | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; | 6 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; |
| 5 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; | 7 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; |
| @@ -51,4 +53,12 @@ public interface IotDataRuleService { | @@ -51,4 +53,12 @@ public interface IotDataRuleService { | ||
| 51 | */ | 53 | */ |
| 52 | PageResult<IotDataRuleDO> getDataRulePage(IotDataRulePageReqVO pageReqVO); | 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 | \ No newline at end of file | 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 | package cn.iocoder.yudao.module.iot.service.rule.data; | 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 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; | 8 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; |
| 6 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; | 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 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; | 11 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; |
| 8 | import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataRuleMapper; | 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 | import jakarta.annotation.Resource; | 16 | import jakarta.annotation.Resource; |
| 10 | import org.springframework.stereotype.Service; | 17 | import org.springframework.stereotype.Service; |
| 11 | import org.springframework.validation.annotation.Validated; | 18 | import org.springframework.validation.annotation.Validated; |
| 12 | 19 | ||
| 20 | +import java.util.*; | ||
| 21 | + | ||
| 13 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 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 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_RULE_NOT_EXISTS; | 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,8 +35,20 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { | ||
| 25 | @Resource | 35 | @Resource |
| 26 | private IotDataRuleMapper dataRuleMapper; | 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 | @Override | 47 | @Override |
| 29 | public Long createDataRule(IotDataRuleSaveReqVO createReqVO) { | 48 | public Long createDataRule(IotDataRuleSaveReqVO createReqVO) { |
| 49 | + // 校验数据源配置和数据目的 | ||
| 50 | + validateDataRuleConfig(createReqVO); | ||
| 51 | + // 新增 | ||
| 30 | IotDataRuleDO dataRule = BeanUtils.toBean(createReqVO, IotDataRuleDO.class); | 52 | IotDataRuleDO dataRule = BeanUtils.toBean(createReqVO, IotDataRuleDO.class); |
| 31 | dataRuleMapper.insert(dataRule); | 53 | dataRuleMapper.insert(dataRule); |
| 32 | return dataRule.getId(); | 54 | return dataRule.getId(); |
| @@ -36,6 +58,9 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { | @@ -36,6 +58,9 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { | ||
| 36 | public void updateDataRule(IotDataRuleSaveReqVO updateReqVO) { | 58 | public void updateDataRule(IotDataRuleSaveReqVO updateReqVO) { |
| 37 | // 校验存在 | 59 | // 校验存在 |
| 38 | validateDataRuleExists(updateReqVO.getId()); | 60 | validateDataRuleExists(updateReqVO.getId()); |
| 61 | + // 校验数据源配置和数据目的 | ||
| 62 | + validateDataRuleConfig(updateReqVO); | ||
| 63 | + | ||
| 39 | // 更新 | 64 | // 更新 |
| 40 | IotDataRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotDataRuleDO.class); | 65 | IotDataRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotDataRuleDO.class); |
| 41 | dataRuleMapper.updateById(updateObj); | 66 | dataRuleMapper.updateById(updateObj); |
| @@ -55,6 +80,55 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { | @@ -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 | @Override | 132 | @Override |
| 59 | public IotDataRuleDO getDataRule(Long id) { | 133 | public IotDataRuleDO getDataRule(Long id) { |
| 60 | return dataRuleMapper.selectById(id); | 134 | return dataRuleMapper.selectById(id); |
| @@ -65,4 +139,9 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { | @@ -65,4 +139,9 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { | ||
| 65 | return dataRuleMapper.selectPage(pageReqVO); | 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 | \ No newline at end of file | 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 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSin | ||
| 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; | 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; |
| 7 | import jakarta.validation.Valid; | 7 | import jakarta.validation.Valid; |
| 8 | 8 | ||
| 9 | +import java.util.Collection; | ||
| 9 | import java.util.List; | 10 | import java.util.List; |
| 10 | 11 | ||
| 11 | /** | 12 | /** |
| @@ -61,4 +62,11 @@ public interface IotDataSinkService { | @@ -61,4 +62,11 @@ public interface IotDataSinkService { | ||
| 61 | */ | 62 | */ |
| 62 | List<IotDataSinkDO> getDataSinkListByStatus(Integer status); | 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 | package cn.iocoder.yudao.module.iot.service.rule.data; | 1 | package cn.iocoder.yudao.module.iot.service.rule.data; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkPageReqVO; | 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,13 +8,16 @@ import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSin | ||
| 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; |
| 8 | import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataSinkMapper; | 9 | import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataSinkMapper; |
| 9 | import jakarta.annotation.Resource; | 10 | import jakarta.annotation.Resource; |
| 11 | +import org.springframework.context.annotation.Lazy; | ||
| 10 | import org.springframework.stereotype.Service; | 12 | import org.springframework.stereotype.Service; |
| 11 | import org.springframework.validation.annotation.Validated; | 13 | import org.springframework.validation.annotation.Validated; |
| 12 | 14 | ||
| 15 | +import java.util.Collection; | ||
| 13 | import java.util.List; | 16 | import java.util.List; |
| 14 | 17 | ||
| 15 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 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 | * IoT 数据流转目的 Service 实现类 | 23 | * IoT 数据流转目的 Service 实现类 |
| @@ -27,6 +31,10 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { | @@ -27,6 +31,10 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { | ||
| 27 | @Resource | 31 | @Resource |
| 28 | private IotDataSinkMapper dataSinkMapper; | 32 | private IotDataSinkMapper dataSinkMapper; |
| 29 | 33 | ||
| 34 | + @Resource | ||
| 35 | + @Lazy // 延迟,避免循环依赖报错 | ||
| 36 | + private IotDataRuleService dataRuleService; | ||
| 37 | + | ||
| 30 | @Override | 38 | @Override |
| 31 | public Long createDataSink(IotDataSinkSaveReqVO createReqVO) { | 39 | public Long createDataSink(IotDataSinkSaveReqVO createReqVO) { |
| 32 | IotDataSinkDO dataBridge = BeanUtils.toBean(createReqVO, IotDataSinkDO.class); | 40 | IotDataSinkDO dataBridge = BeanUtils.toBean(createReqVO, IotDataSinkDO.class); |
| @@ -47,13 +55,17 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { | @@ -47,13 +55,17 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { | ||
| 47 | public void deleteDataSink(Long id) { | 55 | public void deleteDataSink(Long id) { |
| 48 | // 校验存在 | 56 | // 校验存在 |
| 49 | validateDataBridgeExists(id); | 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 | dataSinkMapper.deleteById(id); | 63 | dataSinkMapper.deleteById(id); |
| 52 | } | 64 | } |
| 53 | 65 | ||
| 54 | private void validateDataBridgeExists(Long id) { | 66 | private void validateDataBridgeExists(Long id) { |
| 55 | if (dataSinkMapper.selectById(id) == null) { | 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,4 +84,15 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { | ||
| 72 | return dataSinkMapper.selectListByStatus(status); | 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,6 +9,7 @@ import jakarta.validation.Valid; | ||
| 9 | 9 | ||
| 10 | import java.util.Collection; | 10 | import java.util.Collection; |
| 11 | import java.util.List; | 11 | import java.util.List; |
| 12 | +import java.util.Set; | ||
| 12 | 13 | ||
| 13 | /** | 14 | /** |
| 14 | * IoT 产品物模型 Service 接口 | 15 | * IoT 产品物模型 Service 接口 |
| @@ -99,4 +100,12 @@ public interface IotThingModelService { | @@ -99,4 +100,12 @@ public interface IotThingModelService { | ||
| 99 | */ | 100 | */ |
| 100 | List<IotThingModelDO> getThingModelList(IotThingModelListReqVO reqVO); | 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 | \ No newline at end of file | 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,6 +158,21 @@ public class IotThingModelServiceImpl implements IotThingModelService { | ||
| 158 | return thingModelMapper.selectList(reqVO); | 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 | * |