Commit 27e08266e085064dbf07bda0cee6b0aff3eddb50
Committed by
Gitee
!1269 【代码优化】IoT: 优化数据桥梁
Merge pull request !1269 from puhui999/iot
Showing
30 changed files
with
858 additions
and
470 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java
| ... | ... | @@ -15,5 +15,7 @@ public class DictTypeConstants { |
| 15 | 15 | public static final String VALIDATE_TYPE = "iot_validate_type"; |
| 16 | 16 | |
| 17 | 17 | public static final String DEVICE_STATE = "iot_device_state"; |
| 18 | + public static final String IOT_DATA_BRIDGE_DIRECTION_ENUM = "iot_data_bridge_direction_enum"; | |
| 19 | + public static final String IOT_DATA_BRIDGE_TYPE_ENUM = "iot_data_bridge_type_enum"; | |
| 18 | 20 | |
| 19 | 21 | } | ... | ... |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
| ... | ... | @@ -70,4 +70,7 @@ public interface ErrorCodeConstants { |
| 70 | 70 | // ========== MQTT 通信相关 1-050-009-000 ========== |
| 71 | 71 | ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal"); |
| 72 | 72 | |
| 73 | + // ========== IoT 数据桥梁 1-050-010-000 ========== | |
| 74 | + ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在"); | |
| 75 | + | |
| 73 | 76 | } |
| 74 | 77 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgDirectionEnum.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java
| ... | ... | @@ -13,14 +13,14 @@ import java.util.Arrays; |
| 13 | 13 | */ |
| 14 | 14 | @RequiredArgsConstructor |
| 15 | 15 | @Getter |
| 16 | -public enum IotDataBridgDirectionEnum implements ArrayValuable<Integer> { | |
| 16 | +public enum IotDataBridgeDirectionEnum implements ArrayValuable<Integer> { | |
| 17 | 17 | |
| 18 | 18 | INPUT(1), // 输入 |
| 19 | 19 | OUTPUT(2); // 输出 |
| 20 | 20 | |
| 21 | 21 | private final Integer type; |
| 22 | 22 | |
| 23 | - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgDirectionEnum::getType).toArray(Integer[]::new); | |
| 23 | + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeDirectionEnum::getType).toArray(Integer[]::new); | |
| 24 | 24 | |
| 25 | 25 | @Override |
| 26 | 26 | public Integer[] array() { | ... | ... |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java
| ... | ... | @@ -13,25 +13,26 @@ import java.util.Arrays; |
| 13 | 13 | */ |
| 14 | 14 | @RequiredArgsConstructor |
| 15 | 15 | @Getter |
| 16 | -public enum IotDataBridgTypeEnum implements ArrayValuable<Integer> { | |
| 16 | +public enum IotDataBridgeTypeEnum implements ArrayValuable<Integer> { | |
| 17 | 17 | |
| 18 | - HTTP(1), | |
| 19 | - TCP(2), | |
| 20 | - WEBSOCKET(3), | |
| 18 | + HTTP(1, "HTTP"), | |
| 19 | + TCP(2, "TCP"), | |
| 20 | + WEBSOCKET(3, "WEBSOCKET"), | |
| 21 | 21 | |
| 22 | - MQTT(10), | |
| 22 | + MQTT(10, "MQTT"), | |
| 23 | 23 | |
| 24 | - DATABASE(20), | |
| 25 | - REDIS_STREAM(21), | |
| 24 | + DATABASE(20, "DATABASE"), | |
| 25 | + REDIS_STREAM(21, "REDIS_STREAM"), | |
| 26 | 26 | |
| 27 | - ROCKETMQ(30), | |
| 28 | - RABBITMQ(31), | |
| 29 | - KAFKA(32) | |
| 30 | - ; | |
| 27 | + ROCKETMQ(30, "ROCKETMQ"), | |
| 28 | + RABBITMQ(31, "RABBITMQ"), | |
| 29 | + KAFKA(32, "KAFKA"); | |
| 31 | 30 | |
| 32 | 31 | private final Integer type; |
| 33 | 32 | |
| 34 | - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgTypeEnum::getType).toArray(Integer[]::new); | |
| 33 | + private final String name; | |
| 34 | + | |
| 35 | + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeTypeEnum::getType).toArray(Integer[]::new); | |
| 35 | 36 | |
| 36 | 37 | @Override |
| 37 | 38 | public Integer[] array() { | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 7 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 8 | +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | |
| 9 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; | |
| 10 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeRespVO; | |
| 11 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; | |
| 12 | +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; | |
| 13 | +import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; | |
| 14 | +import io.swagger.v3.oas.annotations.Operation; | |
| 15 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 16 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 17 | +import jakarta.annotation.Resource; | |
| 18 | +import jakarta.servlet.http.HttpServletResponse; | |
| 19 | +import jakarta.validation.Valid; | |
| 20 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 21 | +import org.springframework.validation.annotation.Validated; | |
| 22 | +import org.springframework.web.bind.annotation.*; | |
| 23 | + | |
| 24 | +import java.io.IOException; | |
| 25 | +import java.util.List; | |
| 26 | + | |
| 27 | +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; | |
| 28 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 29 | + | |
| 30 | +@Tag(name = "管理后台 - IoT 数据桥梁") | |
| 31 | +@RestController | |
| 32 | +@RequestMapping("/iot/data-bridge") | |
| 33 | +@Validated | |
| 34 | +public class IotDataBridgeController { | |
| 35 | + | |
| 36 | + @Resource | |
| 37 | + private IotDataBridgeService dataBridgeService; | |
| 38 | + | |
| 39 | + @PostMapping("/create") | |
| 40 | + @Operation(summary = "创建IoT 数据桥梁") | |
| 41 | + @PreAuthorize("@ss.hasPermission('iot:data-bridge:create')") | |
| 42 | + public CommonResult<Long> createDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO createReqVO) { | |
| 43 | + return success(dataBridgeService.createDataBridge(createReqVO)); | |
| 44 | + } | |
| 45 | + | |
| 46 | + @PutMapping("/update") | |
| 47 | + @Operation(summary = "更新IoT 数据桥梁") | |
| 48 | + @PreAuthorize("@ss.hasPermission('iot:data-bridge:update')") | |
| 49 | + public CommonResult<Boolean> updateDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO updateReqVO) { | |
| 50 | + dataBridgeService.updateDataBridge(updateReqVO); | |
| 51 | + return success(true); | |
| 52 | + } | |
| 53 | + | |
| 54 | + @DeleteMapping("/delete") | |
| 55 | + @Operation(summary = "删除IoT 数据桥梁") | |
| 56 | + @Parameter(name = "id", description = "编号", required = true) | |
| 57 | + @PreAuthorize("@ss.hasPermission('iot:data-bridge:delete')") | |
| 58 | + public CommonResult<Boolean> deleteDataBridge(@RequestParam("id") Long id) { | |
| 59 | + dataBridgeService.deleteDataBridge(id); | |
| 60 | + return success(true); | |
| 61 | + } | |
| 62 | + | |
| 63 | + @GetMapping("/get") | |
| 64 | + @Operation(summary = "获得IoT 数据桥梁") | |
| 65 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | |
| 66 | + @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") | |
| 67 | + public CommonResult<IotDataBridgeRespVO> getDataBridge(@RequestParam("id") Long id) { | |
| 68 | + IotDataBridgeDO dataBridge = dataBridgeService.getDataBridge(id); | |
| 69 | + return success(BeanUtils.toBean(dataBridge, IotDataBridgeRespVO.class)); | |
| 70 | + } | |
| 71 | + | |
| 72 | + @GetMapping("/page") | |
| 73 | + @Operation(summary = "获得IoT 数据桥梁分页") | |
| 74 | + @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") | |
| 75 | + public CommonResult<PageResult<IotDataBridgeRespVO>> getDataBridgePage(@Valid IotDataBridgePageReqVO pageReqVO) { | |
| 76 | + PageResult<IotDataBridgeDO> pageResult = dataBridgeService.getDataBridgePage(pageReqVO); | |
| 77 | + return success(BeanUtils.toBean(pageResult, IotDataBridgeRespVO.class)); | |
| 78 | + } | |
| 79 | + | |
| 80 | + @GetMapping("/export-excel") | |
| 81 | + @Operation(summary = "导出IoT 数据桥梁 Excel") | |
| 82 | + @PreAuthorize("@ss.hasPermission('iot:data-bridge:export')") | |
| 83 | + @ApiAccessLog(operateType = EXPORT) | |
| 84 | + public void exportDataBridgeExcel(@Valid IotDataBridgePageReqVO pageReqVO, | |
| 85 | + HttpServletResponse response) throws IOException { | |
| 86 | + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); | |
| 87 | + List<IotDataBridgeDO> list = dataBridgeService.getDataBridgePage(pageReqVO).getList(); | |
| 88 | + // 导出 Excel | |
| 89 | + ExcelUtils.write(response, "IoT 数据桥梁.xls", "数据", IotDataBridgeRespVO.class, | |
| 90 | + BeanUtils.toBean(list, IotDataBridgeRespVO.class)); | |
| 91 | + } | |
| 92 | + | |
| 93 | +} | |
| 0 | 94 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.EqualsAndHashCode; | |
| 7 | +import lombok.ToString; | |
| 8 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 9 | + | |
| 10 | +import java.time.LocalDateTime; | |
| 11 | + | |
| 12 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 13 | + | |
| 14 | +@Schema(description = "管理后台 - IoT 数据桥梁分页 Request VO") | |
| 15 | +@Data | |
| 16 | +@EqualsAndHashCode(callSuper = true) | |
| 17 | +@ToString(callSuper = true) | |
| 18 | +public class IotDataBridgePageReqVO extends PageParam { | |
| 19 | + | |
| 20 | + @Schema(description = "桥梁名称", example = "赵六") | |
| 21 | + private String name; | |
| 22 | + | |
| 23 | + @Schema(description = "桥梁描述", example = "随便") | |
| 24 | + private String description; | |
| 25 | + | |
| 26 | + @Schema(description = "桥梁状态", example = "2") | |
| 27 | + private Integer status; | |
| 28 | + | |
| 29 | + @Schema(description = "桥梁方向") | |
| 30 | + private Integer direction; | |
| 31 | + | |
| 32 | + @Schema(description = "桥梁类型", example = "1") | |
| 33 | + private Integer type; | |
| 34 | + | |
| 35 | + @Schema(description = "创建时间") | |
| 36 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 37 | + private LocalDateTime[] createTime; | |
| 38 | + | |
| 39 | +} | |
| 0 | 40 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | |
| 4 | +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | |
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeConfig; | |
| 6 | +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import com.alibaba.excel.annotation.ExcelProperty; | |
| 8 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 9 | +import lombok.Data; | |
| 10 | + | |
| 11 | +import java.time.LocalDateTime; | |
| 12 | + | |
| 13 | +import static cn.iocoder.yudao.module.iot.enums.DictTypeConstants.IOT_DATA_BRIDGE_DIRECTION_ENUM; | |
| 14 | +import static cn.iocoder.yudao.module.iot.enums.DictTypeConstants.IOT_DATA_BRIDGE_TYPE_ENUM; | |
| 15 | +import static cn.iocoder.yudao.module.system.enums.DictTypeConstants.COMMON_STATUS; | |
| 16 | + | |
| 17 | +@Schema(description = "管理后台 - IoT 数据桥梁 Response VO") | |
| 18 | +@Data | |
| 19 | +@ExcelIgnoreUnannotated | |
| 20 | +public class IotDataBridgeRespVO { | |
| 21 | + | |
| 22 | + @Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564") | |
| 23 | + @ExcelProperty("桥梁编号") | |
| 24 | + private Long id; | |
| 25 | + | |
| 26 | + @Schema(description = "桥梁名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") | |
| 27 | + @ExcelProperty("桥梁名称") | |
| 28 | + private String name; | |
| 29 | + | |
| 30 | + @Schema(description = "桥梁描述", example = "随便") | |
| 31 | + @ExcelProperty("桥梁描述") | |
| 32 | + private String description; | |
| 33 | + | |
| 34 | + @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | |
| 35 | + @ExcelProperty(value = "桥梁状态", converter = DictConvert.class) | |
| 36 | + @DictFormat(COMMON_STATUS) | |
| 37 | + private Integer status; | |
| 38 | + | |
| 39 | + @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 40 | + @ExcelProperty(value = "桥梁方向", converter = DictConvert.class) | |
| 41 | + @DictFormat(IOT_DATA_BRIDGE_DIRECTION_ENUM) | |
| 42 | + private Integer direction; | |
| 43 | + | |
| 44 | + @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 45 | + @ExcelProperty(value = "桥梁类型", converter = DictConvert.class) | |
| 46 | + @DictFormat(IOT_DATA_BRIDGE_TYPE_ENUM) | |
| 47 | + private Integer type; | |
| 48 | + | |
| 49 | + @Schema(description = "桥梁配置") | |
| 50 | + @ExcelProperty("桥梁配置") | |
| 51 | + private IotDataBridgeConfig config; | |
| 52 | + | |
| 53 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 54 | + @ExcelProperty("创建时间") | |
| 55 | + private LocalDateTime createTime; | |
| 56 | + | |
| 57 | +} | |
| 0 | 58 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeConfig; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import jakarta.validation.constraints.NotEmpty; | |
| 6 | +import jakarta.validation.constraints.NotNull; | |
| 7 | +import lombok.Data; | |
| 8 | + | |
| 9 | +@Schema(description = "管理后台 - IoT 数据桥梁新增/修改 Request VO") | |
| 10 | +@Data | |
| 11 | +public class IotDataBridgeSaveReqVO { | |
| 12 | + | |
| 13 | + @Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564") | |
| 14 | + private Long id; | |
| 15 | + | |
| 16 | + @Schema(description = "桥梁名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") | |
| 17 | + @NotEmpty(message = "桥梁名称不能为空") | |
| 18 | + private String name; | |
| 19 | + | |
| 20 | + @Schema(description = "桥梁描述", example = "随便") | |
| 21 | + private String description; | |
| 22 | + | |
| 23 | + @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | |
| 24 | + @NotNull(message = "桥梁状态不能为空") | |
| 25 | + private Integer status; | |
| 26 | + | |
| 27 | + @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 28 | + @NotNull(message = "桥梁方向不能为空") | |
| 29 | + private Integer direction; | |
| 30 | + | |
| 31 | + @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 32 | + @NotNull(message = "桥梁类型不能为空") | |
| 33 | + private Integer type; | |
| 34 | + | |
| 35 | + @Schema(description = "桥梁配置") | |
| 36 | + @NotNull(message = "桥梁配置不能为空") | |
| 37 | + private IotDataBridgeConfig config; | |
| 38 | + | |
| 39 | +} | |
| 0 | 40 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; | |
| 2 | + | |
| 3 | +import com.fasterxml.jackson.annotation.JsonSubTypes; | |
| 4 | +import com.fasterxml.jackson.annotation.JsonTypeInfo; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 抽象类 IotDataBridgeConfig | |
| 9 | + * | |
| 10 | + * 用于表示数据桥梁配置数据的通用类型,根据具体的 "type" 字段动态映射到对应的子类。 | |
| 11 | + * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 | |
| 12 | + * | |
| 13 | + * @author HUIHUI | |
| 14 | + */ | |
| 15 | +@Data | |
| 16 | +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true) | |
| 17 | +@JsonSubTypes({ | |
| 18 | + @JsonSubTypes.Type(value = IotDataBridgeHttpConfig.class, name = "HTTP"), | |
| 19 | + @JsonSubTypes.Type(value = IotDataBridgeKafkaMQConfig.class, name = "KAFKA"), | |
| 20 | + @JsonSubTypes.Type(value = IotDataBridgeMqttConfig.class, name = "MQTT"), | |
| 21 | + @JsonSubTypes.Type(value = IotDataBridgeRabbitMQConfig.class, name = "RABBITMQ"), | |
| 22 | + @JsonSubTypes.Type(value = IotDataBridgeRedisStreamMQConfig.class, name = "REDIS_STREAM"), | |
| 23 | + @JsonSubTypes.Type(value = IotDataBridgeRocketMQConfig.class, name = "ROCKETMQ"), | |
| 24 | +}) | |
| 25 | +public abstract class IotDataBridgeConfig { | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 配置类型 | |
| 29 | + */ | |
| 30 | + private String type; | |
| 31 | + | |
| 32 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +import java.util.Map; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * HTTP 配置 | |
| 9 | + * | |
| 10 | + * @author HUIHUI | |
| 11 | + */ | |
| 12 | +@Data | |
| 13 | +public class IotDataBridgeHttpConfig extends IotDataBridgeConfig { | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * 请求 URL | |
| 17 | + */ | |
| 18 | + private String url; | |
| 19 | + /** | |
| 20 | + * 请求方法 | |
| 21 | + */ | |
| 22 | + private String method; | |
| 23 | + /** | |
| 24 | + * 请求头 | |
| 25 | + */ | |
| 26 | + private Map<String, String> headers; | |
| 27 | + /** | |
| 28 | + * 请求参数 | |
| 29 | + */ | |
| 30 | + private Map<String, String> query; | |
| 31 | + /** | |
| 32 | + * 请求体 | |
| 33 | + */ | |
| 34 | + private String body; | |
| 35 | + | |
| 36 | +} | |
| 0 | 37 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Kafka 配置 | |
| 7 | + * | |
| 8 | + * @author HUIHUI | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +public class IotDataBridgeKafkaMQConfig extends IotDataBridgeConfig { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * Kafka 服务器地址 | |
| 15 | + */ | |
| 16 | + private String bootstrapServers; | |
| 17 | + /** | |
| 18 | + * 用户名 | |
| 19 | + */ | |
| 20 | + private String username; | |
| 21 | + /** | |
| 22 | + * 密码 | |
| 23 | + */ | |
| 24 | + private String password; | |
| 25 | + /** | |
| 26 | + * 是否启用 SSL | |
| 27 | + */ | |
| 28 | + private Boolean ssl; | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * 主题 | |
| 32 | + */ | |
| 33 | + private String topic; | |
| 34 | + | |
| 35 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * MQTT 配置 | |
| 7 | + * | |
| 8 | + * @author HUIHUI | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +public class IotDataBridgeMqttConfig extends IotDataBridgeConfig { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * MQTT 服务器地址 | |
| 15 | + */ | |
| 16 | + private String url; | |
| 17 | + /** | |
| 18 | + * 用户名 | |
| 19 | + */ | |
| 20 | + private String username; | |
| 21 | + /** | |
| 22 | + * 密码 | |
| 23 | + */ | |
| 24 | + private String password; | |
| 25 | + /** | |
| 26 | + * 客户端编号 | |
| 27 | + */ | |
| 28 | + private String clientId; | |
| 29 | + /** | |
| 30 | + * 主题 | |
| 31 | + */ | |
| 32 | + private String topic; | |
| 33 | + | |
| 34 | +} | |
| 0 | 35 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * RabbitMQ 配置 | |
| 7 | + * | |
| 8 | + * @author HUIHUI | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +public class IotDataBridgeRabbitMQConfig extends IotDataBridgeConfig { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * RabbitMQ 服务器地址 | |
| 15 | + */ | |
| 16 | + private String host; | |
| 17 | + /** | |
| 18 | + * 端口 | |
| 19 | + */ | |
| 20 | + private Integer port; | |
| 21 | + /** | |
| 22 | + * 虚拟主机 | |
| 23 | + */ | |
| 24 | + private String virtualHost; | |
| 25 | + /** | |
| 26 | + * 用户名 | |
| 27 | + */ | |
| 28 | + private String username; | |
| 29 | + /** | |
| 30 | + * 密码 | |
| 31 | + */ | |
| 32 | + private String password; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 交换机名称 | |
| 36 | + */ | |
| 37 | + private String exchange; | |
| 38 | + /** | |
| 39 | + * 路由键 | |
| 40 | + */ | |
| 41 | + private String routingKey; | |
| 42 | + /** | |
| 43 | + * 队列名称 | |
| 44 | + */ | |
| 45 | + private String queue; | |
| 46 | +} | |
| 0 | 47 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Redis Stream MQ 配置 | |
| 7 | + * | |
| 8 | + * @author HUIHUI | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +public class IotDataBridgeRedisStreamMQConfig extends IotDataBridgeConfig { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * Redis 服务器地址 | |
| 15 | + */ | |
| 16 | + private String host; | |
| 17 | + /** | |
| 18 | + * 端口 | |
| 19 | + */ | |
| 20 | + private Integer port; | |
| 21 | + /** | |
| 22 | + * 密码 | |
| 23 | + */ | |
| 24 | + private String password; | |
| 25 | + /** | |
| 26 | + * 数据库索引 | |
| 27 | + */ | |
| 28 | + private Integer database; | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * 主题 | |
| 32 | + */ | |
| 33 | + private String topic; | |
| 34 | +} | |
| 0 | 35 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * RocketMQ 配置 | |
| 7 | + * | |
| 8 | + * @author HUIHUI | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +public class IotDataBridgeRocketMQConfig extends IotDataBridgeConfig { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * RocketMQ 名称服务器地址 | |
| 15 | + */ | |
| 16 | + private String nameServer; | |
| 17 | + /** | |
| 18 | + * 访问密钥 | |
| 19 | + */ | |
| 20 | + private String accessKey; | |
| 21 | + /** | |
| 22 | + * 秘密钥匙 | |
| 23 | + */ | |
| 24 | + private String secretKey; | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 生产者组 | |
| 28 | + */ | |
| 29 | + private String group; | |
| 30 | + /** | |
| 31 | + * 主题 | |
| 32 | + */ | |
| 33 | + private String topic; | |
| 34 | + /** | |
| 35 | + * 标签 | |
| 36 | + */ | |
| 37 | + private String tags; | |
| 38 | + | |
| 39 | +} | |
| 0 | 40 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/package-info.java
0 → 100644
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.dal.dataobject.rule; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeConfig; | |
| 5 | +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum; | |
| 6 | +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; | |
| 4 | 7 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 5 | 8 | import com.baomidou.mybatisplus.annotation.TableField; |
| 6 | 9 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | 10 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | 11 | import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; |
| 9 | -import com.fasterxml.jackson.annotation.JsonTypeInfo; | |
| 10 | 12 | import lombok.*; |
| 11 | 13 | |
| 12 | -import java.util.Map; | |
| 13 | - | |
| 14 | 14 | /** |
| 15 | 15 | * IoT 数据桥梁 DO |
| 16 | 16 | * |
| 17 | 17 | * @author 芋道源码 |
| 18 | 18 | */ |
| 19 | -@TableName("iot_data_bridge") | |
| 19 | +@TableName(value = "iot_data_bridge", autoResultMap = true) | |
| 20 | 20 | @KeySequence("iot_data_bridge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 |
| 21 | 21 | @Data |
| 22 | 22 | @EqualsAndHashCode(callSuper = true) |
| ... | ... | @@ -48,14 +48,14 @@ public class IotDataBridgeDO extends BaseDO { |
| 48 | 48 | /** |
| 49 | 49 | * 桥梁方向 |
| 50 | 50 | * |
| 51 | - * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgDirectionEnum} | |
| 51 | + * 枚举 {@link IotDataBridgeDirectionEnum} | |
| 52 | 52 | */ |
| 53 | 53 | private Integer direction; |
| 54 | 54 | |
| 55 | 55 | /** |
| 56 | 56 | * 桥梁类型 |
| 57 | 57 | * |
| 58 | - * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum} | |
| 58 | + * 枚举 {@link IotDataBridgeTypeEnum} | |
| 59 | 59 | */ |
| 60 | 60 | private Integer type; |
| 61 | 61 | |
| ... | ... | @@ -63,211 +63,6 @@ public class IotDataBridgeDO extends BaseDO { |
| 63 | 63 | * 桥梁配置 |
| 64 | 64 | */ |
| 65 | 65 | @TableField(typeHandler = JacksonTypeHandler.class) |
| 66 | - private Config config; | |
| 67 | - | |
| 68 | - /** | |
| 69 | - * 文件客户端的配置 | |
| 70 | - * 不同实现的客户端,需要不同的配置,通过子类来定义 | |
| 71 | - * | |
| 72 | - * @author 芋道源码 | |
| 73 | - */ | |
| 74 | - @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) | |
| 75 | - // @JsonTypeInfo 注解的作用,Jackson 多态 | |
| 76 | - // 1. 序列化到时数据库时,增加 @class 属性。 | |
| 77 | - // 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型 | |
| 78 | - public interface Config { | |
| 79 | - } | |
| 80 | - | |
| 81 | - /** | |
| 82 | - * HTTP 配置 | |
| 83 | - */ | |
| 84 | - @Data | |
| 85 | - public static class HttpConfig implements Config { | |
| 86 | - | |
| 87 | - /** | |
| 88 | - * 请求 URL | |
| 89 | - */ | |
| 90 | - private String url; | |
| 91 | - /** | |
| 92 | - * 请求方法 | |
| 93 | - */ | |
| 94 | - private String method; | |
| 95 | - /** | |
| 96 | - * 请求头 | |
| 97 | - */ | |
| 98 | - private Map<String, String> headers; | |
| 99 | - /** | |
| 100 | - * 请求参数 | |
| 101 | - */ | |
| 102 | - private Map<String, String> query; | |
| 103 | - /** | |
| 104 | - * 请求体 | |
| 105 | - */ | |
| 106 | - private String body; | |
| 107 | - | |
| 108 | - } | |
| 109 | - | |
| 110 | - /** | |
| 111 | - * MQTT 配置 | |
| 112 | - */ | |
| 113 | - @Data | |
| 114 | - public static class MqttConfig implements Config { | |
| 115 | - | |
| 116 | - /** | |
| 117 | - * MQTT 服务器地址 | |
| 118 | - */ | |
| 119 | - private String url; | |
| 120 | - /** | |
| 121 | - * 用户名 | |
| 122 | - */ | |
| 123 | - private String username; | |
| 124 | - /** | |
| 125 | - * 密码 | |
| 126 | - */ | |
| 127 | - private String password; | |
| 128 | - /** | |
| 129 | - * 客户端编号 | |
| 130 | - */ | |
| 131 | - private String clientId; | |
| 132 | - /** | |
| 133 | - * 主题 | |
| 134 | - */ | |
| 135 | - private String topic; | |
| 136 | - | |
| 137 | - } | |
| 138 | - | |
| 139 | - /** | |
| 140 | - * RocketMQ 配置 | |
| 141 | - */ | |
| 142 | - @Data | |
| 143 | - public static class RocketMQConfig implements Config { | |
| 144 | - | |
| 145 | - /** | |
| 146 | - * RocketMQ 名称服务器地址 | |
| 147 | - */ | |
| 148 | - private String nameServer; | |
| 149 | - /** | |
| 150 | - * 访问密钥 | |
| 151 | - */ | |
| 152 | - private String accessKey; | |
| 153 | - /** | |
| 154 | - * 秘密钥匙 | |
| 155 | - */ | |
| 156 | - private String secretKey; | |
| 157 | - | |
| 158 | - /** | |
| 159 | - * 生产者组 | |
| 160 | - */ | |
| 161 | - private String group; | |
| 162 | - /** | |
| 163 | - * 主题 | |
| 164 | - */ | |
| 165 | - private String topic; | |
| 166 | - /** | |
| 167 | - * 标签 | |
| 168 | - */ | |
| 169 | - private String tags; | |
| 170 | - | |
| 171 | - } | |
| 172 | - | |
| 173 | - /** | |
| 174 | - * Kafka 配置 | |
| 175 | - */ | |
| 176 | - @Data | |
| 177 | - public static class KafkaMQConfig implements Config { | |
| 178 | - | |
| 179 | - /** | |
| 180 | - * Kafka 服务器地址 | |
| 181 | - */ | |
| 182 | - private String bootstrapServers; | |
| 183 | - /** | |
| 184 | - * 用户名 | |
| 185 | - */ | |
| 186 | - private String username; | |
| 187 | - /** | |
| 188 | - * 密码 | |
| 189 | - */ | |
| 190 | - private String password; | |
| 191 | - /** | |
| 192 | - * 是否启用 SSL | |
| 193 | - */ | |
| 194 | - private Boolean ssl; | |
| 195 | - | |
| 196 | - /** | |
| 197 | - * 主题 | |
| 198 | - */ | |
| 199 | - private String topic; | |
| 200 | - | |
| 201 | - } | |
| 202 | - | |
| 203 | - /** | |
| 204 | - * RabbitMQ 配置 | |
| 205 | - */ | |
| 206 | - @Data | |
| 207 | - public static class RabbitMQConfig implements Config { | |
| 208 | - | |
| 209 | - /** | |
| 210 | - * RabbitMQ 服务器地址 | |
| 211 | - */ | |
| 212 | - private String host; | |
| 213 | - /** | |
| 214 | - * 端口 | |
| 215 | - */ | |
| 216 | - private Integer port; | |
| 217 | - /** | |
| 218 | - * 虚拟主机 | |
| 219 | - */ | |
| 220 | - private String virtualHost; | |
| 221 | - /** | |
| 222 | - * 用户名 | |
| 223 | - */ | |
| 224 | - private String username; | |
| 225 | - /** | |
| 226 | - * 密码 | |
| 227 | - */ | |
| 228 | - private String password; | |
| 229 | - | |
| 230 | - /** | |
| 231 | - * 交换机名称 | |
| 232 | - */ | |
| 233 | - private String exchange; | |
| 234 | - /** | |
| 235 | - * 路由键 | |
| 236 | - */ | |
| 237 | - private String routingKey; | |
| 238 | - /** | |
| 239 | - * 队列名称 | |
| 240 | - */ | |
| 241 | - private String queue; | |
| 242 | - } | |
| 243 | - | |
| 244 | - /** | |
| 245 | - * Redis Stream MQ 配置 | |
| 246 | - */ | |
| 247 | - @Data | |
| 248 | - public static class RedisStreamMQConfig implements Config { | |
| 249 | - | |
| 250 | - /** | |
| 251 | - * Redis 服务器地址 | |
| 252 | - */ | |
| 253 | - private String host; | |
| 254 | - /** | |
| 255 | - * 端口 | |
| 256 | - */ | |
| 257 | - private Integer port; | |
| 258 | - /** | |
| 259 | - * 密码 | |
| 260 | - */ | |
| 261 | - private String password; | |
| 262 | - /** | |
| 263 | - * 数据库索引 | |
| 264 | - */ | |
| 265 | - private Integer database; | |
| 266 | - | |
| 267 | - /** | |
| 268 | - * 主题 | |
| 269 | - */ | |
| 270 | - private String topic; | |
| 271 | - } | |
| 66 | + private IotDataBridgeConfig config; | |
| 272 | 67 | |
| 273 | 68 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.dal.mysql.rule; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 3 | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 6 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; | |
| 4 | 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; |
| 5 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 9 | |
| 10 | +/** | |
| 11 | + * IoT 数据桥梁 Mapper | |
| 12 | + * | |
| 13 | + * @author HUIHUI | |
| 14 | + */ | |
| 7 | 15 | @Mapper |
| 8 | 16 | public interface IotDataBridgeMapper extends BaseMapperX<IotDataBridgeDO> { |
| 9 | -} | |
| 17 | + | |
| 18 | + default PageResult<IotDataBridgeDO> selectPage(IotDataBridgePageReqVO reqVO) { | |
| 19 | + return selectPage(reqVO, new LambdaQueryWrapperX<IotDataBridgeDO>() | |
| 20 | + .likeIfPresent(IotDataBridgeDO::getName, reqVO.getName()) | |
| 21 | + .likeIfPresent(IotDataBridgeDO::getDescription, reqVO.getDescription()) | |
| 22 | + .eqIfPresent(IotDataBridgeDO::getStatus, reqVO.getStatus()) | |
| 23 | + .eqIfPresent(IotDataBridgeDO::getDirection, reqVO.getDirection()) | |
| 24 | + .eqIfPresent(IotDataBridgeDO::getType, reqVO.getType()) | |
| 25 | + .betweenIfPresent(IotDataBridgeDO::getCreateTime, reqVO.getCreateTime()) | |
| 26 | + .orderByDesc(IotDataBridgeDO::getId)); | |
| 27 | + } | |
| 28 | + | |
| 29 | +} | |
| 10 | 30 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.service.rule; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; | |
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; | |
| 3 | 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; |
| 7 | +import jakarta.validation.Valid; | |
| 4 | 8 | |
| 5 | 9 | /** |
| 6 | - * IoT 数据桥梁的 Service 接口 | |
| 10 | + * IoT 数据桥梁 Service 接口 | |
| 7 | 11 | * |
| 8 | - * @author 芋道源码 | |
| 12 | + * @author HUIHUI | |
| 9 | 13 | */ |
| 10 | 14 | public interface IotDataBridgeService { |
| 11 | 15 | |
| 12 | 16 | /** |
| 13 | - * 获得指定数据桥梁 | |
| 17 | + * 创建IoT 数据桥梁 | |
| 14 | 18 | * |
| 15 | - * @param id 数据桥梁编号 | |
| 16 | - * @return 数据桥梁 | |
| 19 | + * @param createReqVO 创建信息 | |
| 20 | + * @return 编号 | |
| 17 | 21 | */ |
| 18 | - IotDataBridgeDO getIotDataBridge(Long id); | |
| 22 | + Long createDataBridge(@Valid IotDataBridgeSaveReqVO createReqVO); | |
| 19 | 23 | |
| 20 | -} | |
| 24 | + /** | |
| 25 | + * 更新IoT 数据桥梁 | |
| 26 | + * | |
| 27 | + * @param updateReqVO 更新信息 | |
| 28 | + */ | |
| 29 | + void updateDataBridge(@Valid IotDataBridgeSaveReqVO updateReqVO); | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 删除IoT 数据桥梁 | |
| 33 | + * | |
| 34 | + * @param id 编号 | |
| 35 | + */ | |
| 36 | + void deleteDataBridge(Long id); | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 获得IoT 数据桥梁 | |
| 40 | + * | |
| 41 | + * @param id 编号 | |
| 42 | + * @return IoT 数据桥梁 | |
| 43 | + */ | |
| 44 | + IotDataBridgeDO getDataBridge(Long id); | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * 获得IoT 数据桥梁分页 | |
| 48 | + * | |
| 49 | + * @param pageReqVO 分页查询 | |
| 50 | + * @return IoT 数据桥梁分页 | |
| 51 | + */ | |
| 52 | + PageResult<IotDataBridgeDO> getDataBridgePage(IotDataBridgePageReqVO pageReqVO); | |
| 53 | + | |
| 54 | +} | |
| 21 | 55 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.service.rule; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.map.MapUtil; | |
| 4 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; | |
| 5 | 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; |
| 6 | 8 | import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataBridgeMapper; |
| 7 | -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; | |
| 8 | 9 | import jakarta.annotation.Resource; |
| 9 | -import lombok.extern.slf4j.Slf4j; | |
| 10 | 10 | import org.springframework.stereotype.Service; |
| 11 | 11 | import org.springframework.validation.annotation.Validated; |
| 12 | 12 | |
| 13 | -import java.util.Objects; | |
| 13 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 14 | +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_BRIDGE_NOT_EXISTS; | |
| 14 | 15 | |
| 15 | 16 | /** |
| 16 | - * IoT 数据桥梁的 Service 实现类 | |
| 17 | + * IoT 数据桥梁 Service 实现类 | |
| 17 | 18 | * |
| 18 | - * @author 芋道源码 | |
| 19 | + * @author HUIHUI | |
| 19 | 20 | */ |
| 20 | 21 | @Service |
| 21 | 22 | @Validated |
| 22 | -@Slf4j | |
| 23 | 23 | public class IotDataBridgeServiceImpl implements IotDataBridgeService { |
| 24 | 24 | |
| 25 | 25 | @Resource |
| 26 | 26 | private IotDataBridgeMapper dataBridgeMapper; |
| 27 | 27 | |
| 28 | - // TODO @芋艿:临时测试 | |
| 29 | 28 | @Override |
| 30 | - public IotDataBridgeDO getIotDataBridge(Long id) { | |
| 31 | - if (Objects.equals(id, 1L)) { | |
| 32 | - IotDataBridgeDO.HttpConfig config = new IotDataBridgeDO.HttpConfig() | |
| 33 | - .setUrl("http://127.0.0.1:48080/test") | |
| 34 | -// .setMethod("POST") | |
| 35 | - .setMethod("GET") | |
| 36 | - .setQuery(MapUtil.of("aaa", "bbb")) | |
| 37 | - .setHeaders(MapUtil.of("ccc", "ddd")) | |
| 38 | - .setBody(JsonUtils.toJsonString(MapUtil.of("eee", "fff"))); | |
| 39 | - return IotDataBridgeDO.builder().id(1L).name("芋道").description("芋道源码").status(0).direction(1) | |
| 40 | - .type(IotDataBridgTypeEnum.HTTP.getType()).config(config).build(); | |
| 29 | + public Long createDataBridge(IotDataBridgeSaveReqVO createReqVO) { | |
| 30 | + // 插入 | |
| 31 | + IotDataBridgeDO dataBridge = BeanUtils.toBean(createReqVO, IotDataBridgeDO.class); | |
| 32 | + dataBridgeMapper.insert(dataBridge); | |
| 33 | + // 返回 | |
| 34 | + return dataBridge.getId(); | |
| 35 | + } | |
| 36 | + | |
| 37 | + @Override | |
| 38 | + public void updateDataBridge(IotDataBridgeSaveReqVO updateReqVO) { | |
| 39 | + // 校验存在 | |
| 40 | + validateDataBridgeExists(updateReqVO.getId()); | |
| 41 | + // 更新 | |
| 42 | + IotDataBridgeDO updateObj = BeanUtils.toBean(updateReqVO, IotDataBridgeDO.class); | |
| 43 | + dataBridgeMapper.updateById(updateObj); | |
| 44 | + } | |
| 45 | + | |
| 46 | + @Override | |
| 47 | + public void deleteDataBridge(Long id) { | |
| 48 | + // 校验存在 | |
| 49 | + validateDataBridgeExists(id); | |
| 50 | + // 删除 | |
| 51 | + dataBridgeMapper.deleteById(id); | |
| 52 | + } | |
| 53 | + | |
| 54 | + private void validateDataBridgeExists(Long id) { | |
| 55 | + if (dataBridgeMapper.selectById(id) == null) { | |
| 56 | + throw exception(DATA_BRIDGE_NOT_EXISTS); | |
| 41 | 57 | } |
| 58 | + } | |
| 59 | + | |
| 60 | + @Override | |
| 61 | + public IotDataBridgeDO getDataBridge(Long id) { | |
| 42 | 62 | return dataBridgeMapper.selectById(id); |
| 43 | 63 | } |
| 44 | 64 | |
| 45 | -} | |
| 65 | + @Override | |
| 66 | + public PageResult<IotDataBridgeDO> getDataBridgePage(IotDataBridgePageReqVO pageReqVO) { | |
| 67 | + return dataBridgeMapper.selectPage(pageReqVO); | |
| 68 | + } | |
| 69 | + | |
| 70 | +} | |
| 46 | 71 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java
| ... | ... | @@ -22,7 +22,7 @@ public interface IotRuleSceneAction { |
| 22 | 22 | * 2. 非空的情况:设备触发 |
| 23 | 23 | * @param config 配置 |
| 24 | 24 | */ |
| 25 | - void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config); | |
| 25 | + void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) throws Exception; | |
| 26 | 26 | |
| 27 | 27 | /** |
| 28 | 28 | * 获得类型 | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java
| ... | ... | @@ -26,17 +26,17 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { |
| 26 | 26 | @Resource |
| 27 | 27 | private IotDataBridgeService dataBridgeService; |
| 28 | 28 | @Resource |
| 29 | - private List<IotDataBridgeExecute> dataBridgeExecutes; | |
| 29 | + private List<IotDataBridgeExecute<?>> dataBridgeExecutes; | |
| 30 | 30 | |
| 31 | 31 | @Override |
| 32 | - public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { | |
| 32 | + public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) throws Exception { | |
| 33 | 33 | // 1.1 如果消息为空,直接返回 |
| 34 | 34 | if (message == null) { |
| 35 | 35 | return; |
| 36 | 36 | } |
| 37 | 37 | // 1.2 获得数据桥梁 |
| 38 | 38 | Assert.notNull(config.getDataBridgeId(), "数据桥梁编号不能为空"); |
| 39 | - IotDataBridgeDO dataBridge = dataBridgeService.getIotDataBridge(config.getDataBridgeId()); | |
| 39 | + IotDataBridgeDO dataBridge = dataBridgeService.getDataBridge(config.getDataBridgeId()); | |
| 40 | 40 | if (dataBridge == null || dataBridge.getConfig() == null) { |
| 41 | 41 | log.error("[execute][message({}) config({}) 对应的数据桥梁不存在]", message, config); |
| 42 | 42 | return; |
| ... | ... | @@ -47,7 +47,9 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | 49 | // 2. 执行数据桥接操作 |
| 50 | - dataBridgeExecutes.forEach(execute -> execute.execute(message, dataBridge)); | |
| 50 | + for (IotDataBridgeExecute<?> execute : dataBridgeExecutes) { | |
| 51 | + execute.execute(message, dataBridge); | |
| 52 | + } | |
| 51 | 53 | } |
| 52 | 54 | |
| 53 | 55 | @Override | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.service.rule.action.databridge; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; | |
| 4 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | |
| 3 | 5 | import com.google.common.cache.CacheBuilder; |
| 4 | 6 | import com.google.common.cache.CacheLoader; |
| 5 | 7 | import com.google.common.cache.LoadingCache; |
| 8 | +import com.google.common.cache.RemovalListener; | |
| 6 | 9 | import lombok.extern.slf4j.Slf4j; |
| 7 | 10 | |
| 8 | 11 | import java.time.Duration; |
| ... | ... | @@ -15,22 +18,36 @@ import java.time.Duration; |
| 15 | 18 | /** |
| 16 | 19 | * 带缓存功能的数据桥梁执行器抽象类 |
| 17 | 20 | * |
| 21 | + * 该类提供了一个通用的缓存机制,用于管理各类数据桥接的生产者(Producer)实例。 | |
| 22 | + * | |
| 23 | + * 主要特点: | |
| 24 | + * - 基于Guava Cache实现高效的生产者实例缓存管理 | |
| 25 | + * - 自动处理生产者的生命周期(创建、获取、关闭) | |
| 26 | + * - 支持30分钟未访问自动过期清理机制 | |
| 27 | + * - 异常处理与日志记录,便于问题排查 | |
| 28 | + * | |
| 29 | + * 子类需要实现: | |
| 30 | + * - initProducer(Config) - 初始化特定类型的生产者实例 | |
| 31 | + * - closeProducer(Producer) - 关闭生产者实例并释放资源 | |
| 32 | + * | |
| 33 | + * @param <Config> 配置信息类型,用于初始化生产者 | |
| 34 | + * @param <Producer> 生产者类型,负责将数据发送到目标系统 | |
| 18 | 35 | * @author HUIHUI |
| 19 | 36 | */ |
| 20 | 37 | @Slf4j |
| 21 | -public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute { | |
| 38 | +public abstract class AbstractCacheableDataBridgeExecute<Config, Producer> implements IotDataBridgeExecute<Config> { | |
| 22 | 39 | |
| 23 | - // TODO @huihui:AbstractCacheableDataBridgeExecute<Producer> 这样,下面的 Object, Object 就有了类型;另外 IotDataBridgeDO.Config 可以替代一个 Object 哇, | |
| 24 | 40 | /** |
| 25 | 41 | * Producer 缓存 |
| 26 | 42 | */ |
| 27 | - private final LoadingCache<Object, Object> PRODUCER_CACHE = CacheBuilder.newBuilder() | |
| 28 | - .expireAfterAccess(Duration.ofMinutes(30)) | |
| 29 | - .removalListener(notification -> { | |
| 30 | - Object producer = notification.getValue(); | |
| 43 | + private final LoadingCache<Config, Producer> PRODUCER_CACHE = CacheBuilder.newBuilder() | |
| 44 | + .expireAfterAccess(Duration.ofMinutes(30)) // 30 分钟未访问就提前过期 | |
| 45 | + .removalListener((RemovalListener<Config, Producer>) notification -> { | |
| 46 | + Producer producer = notification.getValue(); | |
| 31 | 47 | if (producer == null) { |
| 32 | 48 | return; |
| 33 | 49 | } |
| 50 | + | |
| 34 | 51 | try { |
| 35 | 52 | closeProducer(producer); |
| 36 | 53 | log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已关闭]", notification.getKey()); |
| ... | ... | @@ -38,15 +55,18 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg |
| 38 | 55 | log.error("[PRODUCER_CACHE][配置({}) 对应的 producer 关闭失败]", notification.getKey(), e); |
| 39 | 56 | } |
| 40 | 57 | }) |
| 41 | - .build(new CacheLoader<Object, Object>() { | |
| 42 | - | |
| 58 | + .build(new CacheLoader<Config, Producer>() { | |
| 43 | 59 | @Override |
| 44 | - public Object load(Object config) throws Exception { | |
| 45 | - Object producer = initProducer(config); | |
| 46 | - log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config); | |
| 47 | - return producer; | |
| 60 | + public Producer load(Config config) throws Exception { | |
| 61 | + try { | |
| 62 | + Producer producer = initProducer(config); | |
| 63 | + log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config); | |
| 64 | + return producer; | |
| 65 | + } catch (Exception e) { | |
| 66 | + log.error("[PRODUCER_CACHE][配置({}) 对应的 producer 创建启动失败]", config, e); | |
| 67 | + throw e; // 抛出异常,触发缓存加载失败机制 | |
| 68 | + } | |
| 48 | 69 | } |
| 49 | - | |
| 50 | 70 | }); |
| 51 | 71 | |
| 52 | 72 | /** |
| ... | ... | @@ -55,7 +75,7 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg |
| 55 | 75 | * @param config 配置信息 |
| 56 | 76 | * @return 生产者对象 |
| 57 | 77 | */ |
| 58 | - protected Object getProducer(Object config) throws Exception { | |
| 78 | + protected Producer getProducer(Config config) throws Exception { | |
| 59 | 79 | return PRODUCER_CACHE.get(config); |
| 60 | 80 | } |
| 61 | 81 | |
| ... | ... | @@ -66,13 +86,29 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg |
| 66 | 86 | * @return 生产者对象 |
| 67 | 87 | * @throws Exception 如果初始化失败 |
| 68 | 88 | */ |
| 69 | - protected abstract Object initProducer(Object config) throws Exception; | |
| 89 | + protected abstract Producer initProducer(Config config) throws Exception; | |
| 70 | 90 | |
| 71 | 91 | /** |
| 72 | 92 | * 关闭生产者 |
| 73 | 93 | * |
| 74 | 94 | * @param producer 生产者对象 |
| 75 | 95 | */ |
| 76 | - protected abstract void closeProducer(Object producer); | |
| 96 | + protected abstract void closeProducer(Producer producer) throws Exception; | |
| 97 | + | |
| 98 | + @Override | |
| 99 | + @SuppressWarnings({"unchecked"}) | |
| 100 | + public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { | |
| 101 | + // 1.1 校验数据桥梁类型 | |
| 102 | + if (!getType().equals(dataBridge.getType())) { | |
| 103 | + return; | |
| 104 | + } | |
| 105 | + | |
| 106 | + // 1.2 执行对应的数据桥梁发送消息 | |
| 107 | + try { | |
| 108 | + execute0(message, (Config) dataBridge.getConfig()); | |
| 109 | + } catch (Exception e) { | |
| 110 | + log.error("[execute][桥梁配置 config({}) 对应的 message({}) 发送异常]", dataBridge.getConfig(), message, e); | |
| 111 | + } | |
| 112 | + } | |
| 77 | 113 | |
| 78 | 114 | } |
| 79 | 115 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java
| ... | ... | @@ -9,9 +9,14 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 9 | 9 | * |
| 10 | 10 | * @author HUIHUI |
| 11 | 11 | */ |
| 12 | -public interface IotDataBridgeExecute { | |
| 12 | +public interface IotDataBridgeExecute<Config> { | |
| 13 | 13 | |
| 14 | - // TODO @huihui:要不搞个 getType?然后 execute0 由子类实现。这样,子类的 executeRedisStream ,其实就是 execute0 了。 | |
| 14 | + /** | |
| 15 | + * 获取数据桥梁类型 | |
| 16 | + * | |
| 17 | + * @return 数据桥梁类型 | |
| 18 | + */ | |
| 19 | + Integer getType(); | |
| 15 | 20 | |
| 16 | 21 | /** |
| 17 | 22 | * 执行数据桥梁操作 |
| ... | ... | @@ -19,6 +24,23 @@ public interface IotDataBridgeExecute { |
| 19 | 24 | * @param message 设备消息 |
| 20 | 25 | * @param dataBridge 数据桥梁 |
| 21 | 26 | */ |
| 22 | - void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge); | |
| 27 | + @SuppressWarnings({"unchecked"}) | |
| 28 | + default void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) throws Exception { | |
| 29 | + // 1.1 校验数据桥梁类型 | |
| 30 | + if (!getType().equals(dataBridge.getType())) { | |
| 31 | + return; | |
| 32 | + } | |
| 33 | + | |
| 34 | + // 1.2 执行对应的数据桥梁发送消息 | |
| 35 | + execute0(message, (Config) dataBridge.getConfig()); | |
| 36 | + } | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 【真正】执行数据桥梁操作 | |
| 40 | + * | |
| 41 | + * @param message 设备消息 | |
| 42 | + * @param config 桥梁配置 | |
| 43 | + */ | |
| 44 | + void execute0(IotDeviceMessage message, Config config) throws Exception; | |
| 23 | 45 | |
| 24 | 46 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java
| ... | ... | @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.util.http.HttpUtils; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 6 | -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; | |
| 7 | -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; | |
| 6 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeHttpConfig; | |
| 7 | +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; | |
| 8 | 8 | import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 9 | 9 | import jakarta.annotation.Resource; |
| 10 | 10 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -25,23 +25,19 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ |
| 25 | 25 | */ |
| 26 | 26 | @Component |
| 27 | 27 | @Slf4j |
| 28 | -public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { | |
| 28 | +public class IotHttpDataBridgeExecute implements IotDataBridgeExecute<IotDataBridgeHttpConfig> { | |
| 29 | 29 | |
| 30 | 30 | @Resource |
| 31 | 31 | private RestTemplate restTemplate; |
| 32 | 32 | |
| 33 | 33 | @Override |
| 34 | - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { | |
| 35 | - // 1.1 校验数据桥梁的类型 == HTTP | |
| 36 | - if (!IotDataBridgTypeEnum.HTTP.getType().equals(dataBridge.getType())) { | |
| 37 | - return; | |
| 38 | - } | |
| 39 | - // 1.2 执行 HTTP 请求 | |
| 40 | - executeHttp(message, (IotDataBridgeDO.HttpConfig) dataBridge.getConfig()); | |
| 34 | + public Integer getType() { | |
| 35 | + return IotDataBridgeTypeEnum.HTTP.getType(); | |
| 41 | 36 | } |
| 42 | 37 | |
| 38 | + @Override | |
| 43 | 39 | @SuppressWarnings({"unchecked", "deprecation"}) |
| 44 | - private void executeHttp(IotDeviceMessage message, IotDataBridgeDO.HttpConfig config) { | |
| 40 | + public void execute0(IotDeviceMessage message, IotDataBridgeHttpConfig config) { | |
| 45 | 41 | String url = null; |
| 46 | 42 | HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase()); |
| 47 | 43 | HttpEntity<String> requestEntity = null; | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.service.rule.action.databridge; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeKafkaMQConfig; | |
| 3 | 4 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; |
| 4 | -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; | |
| 5 | +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; | |
| 5 | 6 | import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 6 | 7 | import lombok.extern.slf4j.Slf4j; |
| 7 | 8 | import org.apache.kafka.clients.producer.ProducerConfig; |
| 8 | 9 | import org.apache.kafka.common.serialization.StringSerializer; |
| 10 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | |
| 9 | 11 | import org.springframework.kafka.core.DefaultKafkaProducerFactory; |
| 10 | 12 | import org.springframework.kafka.core.KafkaTemplate; |
| 11 | 13 | import org.springframework.stereotype.Component; |
| ... | ... | @@ -15,65 +17,53 @@ import java.time.LocalDateTime; |
| 15 | 17 | import java.util.HashMap; |
| 16 | 18 | import java.util.Map; |
| 17 | 19 | import java.util.concurrent.TimeUnit; |
| 18 | -import java.util.concurrent.TimeoutException; | |
| 19 | 20 | |
| 20 | 21 | /** |
| 21 | 22 | * Kafka 的 {@link IotDataBridgeExecute} 实现类 |
| 22 | 23 | * |
| 23 | 24 | * @author HUIHUI |
| 24 | 25 | */ |
| 26 | +@ConditionalOnClass(name = "org.springframework.kafka.core.KafkaTemplate") | |
| 25 | 27 | @Component |
| 26 | 28 | @Slf4j |
| 27 | -public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { | |
| 29 | +public class IotKafkaMQDataBridgeExecute extends | |
| 30 | + AbstractCacheableDataBridgeExecute<IotDataBridgeKafkaMQConfig, KafkaTemplate<String, String>> { | |
| 28 | 31 | |
| 29 | - private static final Duration SEND_TIMEOUT = Duration.ofMillis(10); | |
| 32 | + private static final Duration SEND_TIMEOUT = Duration.ofMillis(10000); // 10 秒超时时间 | |
| 30 | 33 | |
| 31 | 34 | @Override |
| 32 | - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { | |
| 33 | - // 1. 校验数据桥梁的类型 == KAFKA | |
| 34 | - if (!IotDataBridgTypeEnum.KAFKA.getType().equals(dataBridge.getType())) { | |
| 35 | - return; | |
| 36 | - } | |
| 37 | - // 2. 执行 Kafka 发送消息 | |
| 38 | - executeKafka(message, (IotDataBridgeDO.KafkaMQConfig) dataBridge.getConfig()); | |
| 35 | + public Integer getType() { | |
| 36 | + return IotDataBridgeTypeEnum.KAFKA.getType(); | |
| 39 | 37 | } |
| 40 | 38 | |
| 41 | - @SuppressWarnings("unchecked") | |
| 42 | - private void executeKafka(IotDeviceMessage message, IotDataBridgeDO.KafkaMQConfig config) { | |
| 43 | - try { | |
| 44 | - // 1. 获取或创建 KafkaTemplate | |
| 45 | - KafkaTemplate<String, String> kafkaTemplate = (KafkaTemplate<String, String>) getProducer(config); | |
| 46 | - | |
| 47 | - // 2. 发送消息并等待结果 | |
| 48 | - kafkaTemplate.send(config.getTopic(), message.toString()) | |
| 49 | - .get(SEND_TIMEOUT.getSeconds(), TimeUnit.SECONDS); // 添加超时等待 | |
| 50 | - log.info("[executeKafka][message({}) 发送成功]", message); | |
| 51 | - } catch (TimeoutException e) { | |
| 52 | - log.error("[executeKafka][message({}) config({}) 发送超时]", message, config, e); | |
| 53 | - } catch (Exception e) { | |
| 54 | - log.error("[executeKafka][message({}) config({}) 发送异常]", message, config, e); | |
| 55 | - } | |
| 39 | + @Override | |
| 40 | + public void execute0(IotDeviceMessage message, IotDataBridgeKafkaMQConfig config) throws Exception { | |
| 41 | + // 1. 获取或创建 KafkaTemplate | |
| 42 | + KafkaTemplate<String, String> kafkaTemplate = getProducer(config); | |
| 43 | + | |
| 44 | + // 2. 发送消息并等待结果 | |
| 45 | + kafkaTemplate.send(config.getTopic(), message.toString()) | |
| 46 | + .get(SEND_TIMEOUT.getSeconds(), TimeUnit.SECONDS); // 添加超时等待 | |
| 47 | + log.info("[execute0][message({}) 发送成功]", message); | |
| 56 | 48 | } |
| 57 | 49 | |
| 58 | 50 | @Override |
| 59 | - protected Object initProducer(Object config) { | |
| 60 | - IotDataBridgeDO.KafkaMQConfig kafkaConfig = (IotDataBridgeDO.KafkaMQConfig) config; | |
| 61 | - | |
| 51 | + protected KafkaTemplate<String, String> initProducer(IotDataBridgeKafkaMQConfig config) { | |
| 62 | 52 | // 1.1 构建生产者配置 |
| 63 | 53 | Map<String, Object> props = new HashMap<>(); |
| 64 | - props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServers()); | |
| 54 | + props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, config.getBootstrapServers()); | |
| 65 | 55 | props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); |
| 66 | 56 | props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); |
| 67 | 57 | // 1.2 如果配置了认证信息 |
| 68 | - if (kafkaConfig.getUsername() != null && kafkaConfig.getPassword() != null) { | |
| 58 | + if (config.getUsername() != null && config.getPassword() != null) { | |
| 69 | 59 | props.put("security.protocol", "SASL_PLAINTEXT"); |
| 70 | 60 | props.put("sasl.mechanism", "PLAIN"); |
| 71 | 61 | props.put("sasl.jaas.config", |
| 72 | 62 | "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"" |
| 73 | - + kafkaConfig.getUsername() + "\" password=\"" + kafkaConfig.getPassword() + "\";"); | |
| 63 | + + config.getUsername() + "\" password=\"" + config.getPassword() + "\";"); | |
| 74 | 64 | } |
| 75 | 65 | // 1.3 如果启用 SSL |
| 76 | - if (Boolean.TRUE.equals(kafkaConfig.getSsl())) { | |
| 66 | + if (Boolean.TRUE.equals(config.getSsl())) { | |
| 77 | 67 | props.put("security.protocol", "SSL"); |
| 78 | 68 | } |
| 79 | 69 | |
| ... | ... | @@ -83,10 +73,8 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec |
| 83 | 73 | } |
| 84 | 74 | |
| 85 | 75 | @Override |
| 86 | - protected void closeProducer(Object producer) { | |
| 87 | - if (producer instanceof KafkaTemplate) { | |
| 88 | - ((KafkaTemplate<?, ?>) producer).destroy(); | |
| 89 | - } | |
| 76 | + protected void closeProducer(KafkaTemplate<String, String> producer) { | |
| 77 | + producer.destroy(); | |
| 90 | 78 | } |
| 91 | 79 | |
| 92 | 80 | // TODO @芋艿:测试代码,后续清理 |
| ... | ... | @@ -95,7 +83,7 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec |
| 95 | 83 | IotKafkaMQDataBridgeExecute action = new IotKafkaMQDataBridgeExecute(); |
| 96 | 84 | |
| 97 | 85 | // 2. 创建共享的配置 |
| 98 | - IotDataBridgeDO.KafkaMQConfig config = new IotDataBridgeDO.KafkaMQConfig(); | |
| 86 | + IotDataBridgeKafkaMQConfig config = new IotDataBridgeKafkaMQConfig(); | |
| 99 | 87 | config.setBootstrapServers("127.0.0.1:9092"); |
| 100 | 88 | config.setTopic("test-topic"); |
| 101 | 89 | config.setSsl(false); |
| ... | ... | @@ -117,10 +105,10 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec |
| 117 | 105 | |
| 118 | 106 | // 4. 执行两次测试,验证缓存 |
| 119 | 107 | log.info("[main][第一次执行,应该会创建新的 producer]"); |
| 120 | - action.executeKafka(message, config); | |
| 108 | + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); | |
| 121 | 109 | |
| 122 | 110 | log.info("[main][第二次执行,应该会复用缓存的 producer]"); |
| 123 | - action.executeKafka(message, config); | |
| 111 | + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); | |
| 124 | 112 | } |
| 125 | 113 | |
| 126 | 114 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.service.rule.action.databridge; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeRabbitMQConfig; | |
| 3 | 4 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; |
| 4 | -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; | |
| 5 | +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; | |
| 5 | 6 | import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 6 | 7 | import com.rabbitmq.client.Channel; |
| 7 | 8 | import com.rabbitmq.client.Connection; |
| 8 | 9 | import com.rabbitmq.client.ConnectionFactory; |
| 9 | 10 | import lombok.extern.slf4j.Slf4j; |
| 11 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | |
| 10 | 12 | import org.springframework.stereotype.Component; |
| 11 | 13 | |
| 12 | 14 | import java.nio.charset.StandardCharsets; |
| ... | ... | @@ -17,51 +19,44 @@ import java.time.LocalDateTime; |
| 17 | 19 | * |
| 18 | 20 | * @author HUIHUI |
| 19 | 21 | */ |
| 22 | +@ConditionalOnClass(name = "com.rabbitmq.client.Channel") | |
| 20 | 23 | @Component |
| 21 | 24 | @Slf4j |
| 22 | -public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { | |
| 25 | +public class IotRabbitMQDataBridgeExecute extends | |
| 26 | + AbstractCacheableDataBridgeExecute<IotDataBridgeRabbitMQConfig, Channel> { | |
| 27 | + | |
| 23 | 28 | |
| 24 | 29 | @Override |
| 25 | - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { | |
| 26 | - // 1.1 校验数据桥梁的类型 == RABBITMQ | |
| 27 | - if (!IotDataBridgTypeEnum.RABBITMQ.getType().equals(dataBridge.getType())) { | |
| 28 | - return; | |
| 29 | - } | |
| 30 | - // 1.2 执行 RabbitMQ 发送消息 | |
| 31 | - executeRabbitMQ(message, (IotDataBridgeDO.RabbitMQConfig) dataBridge.getConfig()); | |
| 30 | + public Integer getType() { | |
| 31 | + return IotDataBridgeTypeEnum.RABBITMQ.getType(); | |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | - private void executeRabbitMQ(IotDeviceMessage message, IotDataBridgeDO.RabbitMQConfig config) { | |
| 35 | - try { | |
| 36 | - // 1. 获取或创建 Channel | |
| 37 | - Channel channel = (Channel) getProducer(config); | |
| 38 | - | |
| 39 | - // 2.1 声明交换机、队列和绑定关系 | |
| 40 | - channel.exchangeDeclare(config.getExchange(), "direct", true); | |
| 41 | - channel.queueDeclare(config.getQueue(), true, false, false, null); | |
| 42 | - channel.queueBind(config.getQueue(), config.getExchange(), config.getRoutingKey()); | |
| 43 | - | |
| 44 | - // 2.2 发送消息 | |
| 45 | - channel.basicPublish(config.getExchange(), config.getRoutingKey(), null, | |
| 46 | - message.toString().getBytes(StandardCharsets.UTF_8)); | |
| 47 | - log.info("[executeRabbitMQ][message({}) config({}) 发送成功]", message, config); | |
| 48 | - } catch (Exception e) { | |
| 49 | - log.error("[executeRabbitMQ][message({}) config({}) 发送异常]", message, config, e); | |
| 50 | - } | |
| 34 | + @Override | |
| 35 | + public void execute0(IotDeviceMessage message, IotDataBridgeRabbitMQConfig config) throws Exception { | |
| 36 | + // 1. 获取或创建 Channel | |
| 37 | + Channel channel = getProducer(config); | |
| 38 | + | |
| 39 | + // 2.1 声明交换机、队列和绑定关系 | |
| 40 | + channel.exchangeDeclare(config.getExchange(), "direct", true); | |
| 41 | + channel.queueDeclare(config.getQueue(), true, false, false, null); | |
| 42 | + channel.queueBind(config.getQueue(), config.getExchange(), config.getRoutingKey()); | |
| 43 | + | |
| 44 | + // 2.2 发送消息 | |
| 45 | + channel.basicPublish(config.getExchange(), config.getRoutingKey(), null, | |
| 46 | + message.toString().getBytes(StandardCharsets.UTF_8)); | |
| 47 | + log.info("[executeRabbitMQ][message({}) config({}) 发送成功]", message, config); | |
| 51 | 48 | } |
| 52 | 49 | |
| 53 | 50 | @Override |
| 54 | 51 | @SuppressWarnings("resource") |
| 55 | - protected Object initProducer(Object config) throws Exception { | |
| 56 | - IotDataBridgeDO.RabbitMQConfig rabbitConfig = (IotDataBridgeDO.RabbitMQConfig) config; | |
| 57 | - | |
| 52 | + protected Channel initProducer(IotDataBridgeRabbitMQConfig config) throws Exception { | |
| 58 | 53 | // 1. 创建连接工厂 |
| 59 | 54 | ConnectionFactory factory = new ConnectionFactory(); |
| 60 | - factory.setHost(rabbitConfig.getHost()); | |
| 61 | - factory.setPort(rabbitConfig.getPort()); | |
| 62 | - factory.setVirtualHost(rabbitConfig.getVirtualHost()); | |
| 63 | - factory.setUsername(rabbitConfig.getUsername()); | |
| 64 | - factory.setPassword(rabbitConfig.getPassword()); | |
| 55 | + factory.setHost(config.getHost()); | |
| 56 | + factory.setPort(config.getPort()); | |
| 57 | + factory.setVirtualHost(config.getVirtualHost()); | |
| 58 | + factory.setUsername(config.getUsername()); | |
| 59 | + factory.setPassword(config.getPassword()); | |
| 65 | 60 | |
| 66 | 61 | // 2. 创建连接 |
| 67 | 62 | Connection connection = factory.newConnection(); |
| ... | ... | @@ -71,20 +66,13 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe |
| 71 | 66 | } |
| 72 | 67 | |
| 73 | 68 | @Override |
| 74 | - protected void closeProducer(Object producer) { | |
| 75 | - if (producer instanceof Channel) { | |
| 76 | - try { | |
| 77 | - Channel channel = (Channel) producer; | |
| 78 | - if (channel.isOpen()) { | |
| 79 | - channel.close(); | |
| 80 | - } | |
| 81 | - Connection connection = channel.getConnection(); | |
| 82 | - if (connection.isOpen()) { | |
| 83 | - connection.close(); | |
| 84 | - } | |
| 85 | - } catch (Exception e) { | |
| 86 | - log.error("[closeProducer][关闭 RabbitMQ 连接异常]", e); | |
| 87 | - } | |
| 69 | + protected void closeProducer(Channel channel) throws Exception { | |
| 70 | + if (channel.isOpen()) { | |
| 71 | + channel.close(); | |
| 72 | + } | |
| 73 | + Connection connection = channel.getConnection(); | |
| 74 | + if (connection.isOpen()) { | |
| 75 | + connection.close(); | |
| 88 | 76 | } |
| 89 | 77 | } |
| 90 | 78 | |
| ... | ... | @@ -94,7 +82,7 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe |
| 94 | 82 | IotRabbitMQDataBridgeExecute action = new IotRabbitMQDataBridgeExecute(); |
| 95 | 83 | |
| 96 | 84 | // 2. 创建共享的配置 |
| 97 | - IotDataBridgeDO.RabbitMQConfig config = new IotDataBridgeDO.RabbitMQConfig(); | |
| 85 | + IotDataBridgeRabbitMQConfig config = new IotDataBridgeRabbitMQConfig(); | |
| 98 | 86 | config.setHost("localhost"); |
| 99 | 87 | config.setPort(5672); |
| 100 | 88 | config.setVirtualHost("/"); |
| ... | ... | @@ -118,10 +106,12 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe |
| 118 | 106 | .build(); |
| 119 | 107 | |
| 120 | 108 | // 4. 执行两次测试,验证缓存 |
| 121 | - log.info("[main][第一次执行,应该会创建新的 channel]"); | |
| 122 | - action.executeRabbitMQ(message, config); | |
| 109 | + // 4. 执行两次测试,验证缓存 | |
| 110 | + log.info("[main][第一次执行,应该会创建新的 producer]"); | |
| 111 | + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); | |
| 123 | 112 | |
| 124 | - log.info("[main][第二次执行,应该会复用缓存的 channel]"); | |
| 125 | - action.executeRabbitMQ(message, config); | |
| 113 | + log.info("[main][第二次执行,应该会复用缓存的 producer]"); | |
| 114 | + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); | |
| 126 | 115 | } |
| 116 | + | |
| 127 | 117 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java
| ... | ... | @@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ReflectUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeRedisStreamMQConfig; | |
| 5 | 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; |
| 6 | -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; | |
| 7 | +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; | |
| 7 | 8 | import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 8 | 9 | import com.fasterxml.jackson.databind.ObjectMapper; |
| 9 | 10 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; |
| ... | ... | @@ -29,47 +30,36 @@ import java.time.LocalDateTime; |
| 29 | 30 | */ |
| 30 | 31 | @Component |
| 31 | 32 | @Slf4j |
| 32 | -public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { | |
| 33 | +public class IotRedisStreamMQDataBridgeExecute extends | |
| 34 | + AbstractCacheableDataBridgeExecute<IotDataBridgeRedisStreamMQConfig, RedisTemplate<String, Object>> { | |
| 33 | 35 | |
| 34 | 36 | @Override |
| 35 | - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { | |
| 36 | - // 1.1 校验数据桥梁类型 | |
| 37 | - if (!IotDataBridgTypeEnum.REDIS_STREAM.getType().equals(dataBridge.getType())) { | |
| 38 | - return; | |
| 39 | - } | |
| 40 | - // 1.2 执行消息发送 | |
| 41 | - executeRedisStream(message, (IotDataBridgeDO.RedisStreamMQConfig) dataBridge.getConfig()); | |
| 37 | + public Integer getType() { | |
| 38 | + return IotDataBridgeTypeEnum.REDIS_STREAM.getType(); | |
| 42 | 39 | } |
| 43 | 40 | |
| 44 | - @SuppressWarnings("unchecked") | |
| 45 | - // TODO @huihui:try catch 交给父类来做,子类不处理异常 | |
| 46 | - private void executeRedisStream(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) { | |
| 47 | - try { | |
| 48 | - // 1. 获取 RedisTemplate | |
| 49 | - RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) getProducer(config); | |
| 50 | - | |
| 51 | - // 2. 创建并发送 Stream 记录 | |
| 52 | - ObjectRecord<String, IotDeviceMessage> record = StreamRecords.newRecord() | |
| 53 | - .ofObject(message).withStreamKey(config.getTopic()); | |
| 54 | - String recordId = String.valueOf(redisTemplate.opsForStream().add(record)); | |
| 55 | - log.info("[executeRedisStream][消息发送成功] messageId: {}, config: {}", recordId, config); | |
| 56 | - } catch (Exception e) { | |
| 57 | - log.error("[executeRedisStream][消息发送失败] message: {}, config: {}", message, config, e); | |
| 58 | - } | |
| 41 | + @Override | |
| 42 | + public void execute0(IotDeviceMessage message, IotDataBridgeRedisStreamMQConfig config) throws Exception { | |
| 43 | + // 1. 获取 RedisTemplate | |
| 44 | + RedisTemplate<String, Object> redisTemplate = getProducer(config); | |
| 45 | + | |
| 46 | + // 2. 创建并发送 Stream 记录 | |
| 47 | + ObjectRecord<String, IotDeviceMessage> record = StreamRecords.newRecord() | |
| 48 | + .ofObject(message).withStreamKey(config.getTopic()); | |
| 49 | + String recordId = String.valueOf(redisTemplate.opsForStream().add(record)); | |
| 50 | + log.info("[executeRedisStream][消息发送成功] messageId: {}, config: {}", recordId, config); | |
| 59 | 51 | } |
| 60 | 52 | |
| 61 | 53 | @Override |
| 62 | - protected Object initProducer(Object config) { | |
| 63 | - IotDataBridgeDO.RedisStreamMQConfig redisConfig = (IotDataBridgeDO.RedisStreamMQConfig) config; | |
| 64 | - | |
| 54 | + protected RedisTemplate<String, Object> initProducer(IotDataBridgeRedisStreamMQConfig config) { | |
| 65 | 55 | // 1.1 创建 Redisson 配置 |
| 66 | 56 | Config redissonConfig = new Config(); |
| 67 | 57 | SingleServerConfig serverConfig = redissonConfig.useSingleServer() |
| 68 | - .setAddress("redis://" + redisConfig.getHost() + ":" + redisConfig.getPort()) | |
| 69 | - .setDatabase(redisConfig.getDatabase()); | |
| 58 | + .setAddress("redis://" + config.getHost() + ":" + config.getPort()) | |
| 59 | + .setDatabase(config.getDatabase()); | |
| 70 | 60 | // 1.2 设置密码(如果有) |
| 71 | - if (StrUtil.isNotBlank(redisConfig.getPassword())) { | |
| 72 | - serverConfig.setPassword(redisConfig.getPassword()); | |
| 61 | + if (StrUtil.isNotBlank(config.getPassword())) { | |
| 62 | + serverConfig.setPassword(config.getPassword()); | |
| 73 | 63 | } |
| 74 | 64 | |
| 75 | 65 | // TODO @huihui:看看能不能简化一些。按道理说,不用这么多的哈。 |
| ... | ... | @@ -90,17 +80,10 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid |
| 90 | 80 | } |
| 91 | 81 | |
| 92 | 82 | @Override |
| 93 | - protected void closeProducer(Object producer) { | |
| 94 | - // TODO @huihui:try catch 交给父类来做。子类不处理异常 | |
| 95 | - if (producer instanceof RedisTemplate) { | |
| 96 | - RedisConnectionFactory factory = ((RedisTemplate<?, ?>) producer).getConnectionFactory(); | |
| 97 | - try { | |
| 98 | - if (factory != null) { | |
| 99 | - ((RedissonConnectionFactory) factory).destroy(); | |
| 100 | - } | |
| 101 | - } catch (Exception e) { | |
| 102 | - log.error("[closeProducer][关闭 redisson 连接异常]", e); | |
| 103 | - } | |
| 83 | + protected void closeProducer(RedisTemplate<String, Object> producer) throws Exception { | |
| 84 | + RedisConnectionFactory factory = producer.getConnectionFactory(); | |
| 85 | + if (factory != null) { | |
| 86 | + ((RedissonConnectionFactory) factory).destroy(); | |
| 104 | 87 | } |
| 105 | 88 | } |
| 106 | 89 | |
| ... | ... | @@ -119,7 +102,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid |
| 119 | 102 | IotRedisStreamMQDataBridgeExecute action = new IotRedisStreamMQDataBridgeExecute(); |
| 120 | 103 | |
| 121 | 104 | // 2. 创建共享的配置 |
| 122 | - IotDataBridgeDO.RedisStreamMQConfig config = new IotDataBridgeDO.RedisStreamMQConfig(); | |
| 105 | + IotDataBridgeRedisStreamMQConfig config = new IotDataBridgeRedisStreamMQConfig(); | |
| 123 | 106 | config.setHost("127.0.0.1"); |
| 124 | 107 | config.setPort(6379); |
| 125 | 108 | config.setDatabase(0); |
| ... | ... | @@ -140,11 +123,11 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid |
| 140 | 123 | .build(); |
| 141 | 124 | |
| 142 | 125 | // 4. 执行两次测试,验证缓存 |
| 143 | - log.info("[main][第一次执行,应该会创建新的 RedisTemplate]"); | |
| 144 | - action.executeRedisStream(message, config); | |
| 126 | + log.info("[main][第一次执行,应该会创建新的 producer]"); | |
| 127 | + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); | |
| 145 | 128 | |
| 146 | - log.info("[main][第二次执行,应该会复用缓存的 RedisTemplate]"); | |
| 147 | - action.executeRedisStream(message, config); | |
| 129 | + log.info("[main][第二次执行,应该会复用缓存的 producer]"); | |
| 130 | + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); | |
| 148 | 131 | } |
| 149 | 132 | |
| 150 | 133 | } |
| 151 | 134 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.service.rule.action.databridge; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeRocketMQConfig; | |
| 3 | 4 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; |
| 4 | -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; | |
| 5 | +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; | |
| 5 | 6 | import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 6 | 7 | import lombok.extern.slf4j.Slf4j; |
| 7 | 8 | import org.apache.rocketmq.client.producer.DefaultMQProducer; |
| ... | ... | @@ -9,6 +10,7 @@ import org.apache.rocketmq.client.producer.SendResult; |
| 9 | 10 | import org.apache.rocketmq.client.producer.SendStatus; |
| 10 | 11 | import org.apache.rocketmq.common.message.Message; |
| 11 | 12 | import org.apache.rocketmq.remoting.common.RemotingHelper; |
| 13 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | |
| 12 | 14 | import org.springframework.stereotype.Component; |
| 13 | 15 | |
| 14 | 16 | import java.time.LocalDateTime; |
| ... | ... | @@ -18,58 +20,49 @@ import java.time.LocalDateTime; |
| 18 | 20 | * |
| 19 | 21 | * @author HUIHUI |
| 20 | 22 | */ |
| 23 | +@ConditionalOnClass(name = "org.apache.rocketmq.client.producer.DefaultMQProducer") | |
| 21 | 24 | @Component |
| 22 | 25 | @Slf4j |
| 23 | -public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { | |
| 26 | +public class IotRocketMQDataBridgeExecute extends | |
| 27 | + AbstractCacheableDataBridgeExecute<IotDataBridgeRocketMQConfig, DefaultMQProducer> { | |
| 24 | 28 | |
| 25 | 29 | @Override |
| 26 | - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { | |
| 27 | - // 1.1 校验数据桥梁的类型 == ROCKETMQ | |
| 28 | - if (!IotDataBridgTypeEnum.ROCKETMQ.getType().equals(dataBridge.getType())) { | |
| 29 | - return; | |
| 30 | - } | |
| 31 | - // 1.2 执行 RocketMQ 发送消息 | |
| 32 | - executeRocketMQ(message, (IotDataBridgeDO.RocketMQConfig) dataBridge.getConfig()); | |
| 30 | + public Integer getType() { | |
| 31 | + return IotDataBridgeTypeEnum.ROCKETMQ.getType(); | |
| 33 | 32 | } |
| 34 | 33 | |
| 35 | - private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { | |
| 36 | - try { | |
| 37 | - // 1. 获取或创建 Producer | |
| 38 | - DefaultMQProducer producer = (DefaultMQProducer) getProducer(config); | |
| 34 | + @Override | |
| 35 | + public void execute0(IotDeviceMessage message, IotDataBridgeRocketMQConfig config) throws Exception { | |
| 36 | + // 1. 获取或创建 Producer | |
| 37 | + DefaultMQProducer producer = getProducer(config); | |
| 39 | 38 | |
| 40 | - // 2.1 创建消息对象,指定Topic、Tag和消息体 | |
| 41 | - Message msg = new Message( | |
| 42 | - config.getTopic(), | |
| 43 | - config.getTags(), | |
| 44 | - message.toString().getBytes(RemotingHelper.DEFAULT_CHARSET) | |
| 45 | - ); | |
| 46 | - // 2.2 发送同步消息并处理结果 | |
| 47 | - SendResult sendResult = producer.send(msg); | |
| 48 | - // 2.3 处理发送结果 | |
| 49 | - if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { | |
| 50 | - log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", message, config, sendResult); | |
| 51 | - } else { | |
| 52 | - log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", message, config, sendResult); | |
| 53 | - } | |
| 54 | - } catch (Exception e) { | |
| 55 | - log.error("[executeRocketMQ][message({}) config({}) 发送异常]", message, config, e); | |
| 39 | + // 2.1 创建消息对象,指定Topic、Tag和消息体 | |
| 40 | + Message msg = new Message( | |
| 41 | + config.getTopic(), | |
| 42 | + config.getTags(), | |
| 43 | + message.toString().getBytes(RemotingHelper.DEFAULT_CHARSET) | |
| 44 | + ); | |
| 45 | + // 2.2 发送同步消息并处理结果 | |
| 46 | + SendResult sendResult = producer.send(msg); | |
| 47 | + // 2.3 处理发送结果 | |
| 48 | + if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { | |
| 49 | + log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", message, config, sendResult); | |
| 50 | + } else { | |
| 51 | + log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", message, config, sendResult); | |
| 56 | 52 | } |
| 57 | 53 | } |
| 58 | 54 | |
| 59 | 55 | @Override |
| 60 | - protected Object initProducer(Object config) throws Exception { | |
| 61 | - IotDataBridgeDO.RocketMQConfig rocketMQConfig = (IotDataBridgeDO.RocketMQConfig) config; | |
| 62 | - DefaultMQProducer producer = new DefaultMQProducer(rocketMQConfig.getGroup()); | |
| 63 | - producer.setNamesrvAddr(rocketMQConfig.getNameServer()); | |
| 56 | + protected DefaultMQProducer initProducer(IotDataBridgeRocketMQConfig config) throws Exception { | |
| 57 | + DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); | |
| 58 | + producer.setNamesrvAddr(config.getNameServer()); | |
| 64 | 59 | producer.start(); |
| 65 | 60 | return producer; |
| 66 | 61 | } |
| 67 | 62 | |
| 68 | 63 | @Override |
| 69 | - protected void closeProducer(Object producer) { | |
| 70 | - if (producer instanceof DefaultMQProducer) { | |
| 71 | - ((DefaultMQProducer) producer).shutdown(); | |
| 72 | - } | |
| 64 | + protected void closeProducer(DefaultMQProducer producer) { | |
| 65 | + producer.shutdown(); | |
| 73 | 66 | } |
| 74 | 67 | |
| 75 | 68 | // TODO @芋艿:测试代码,后续清理 |
| ... | ... | @@ -78,7 +71,7 @@ public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExe |
| 78 | 71 | IotRocketMQDataBridgeExecute action = new IotRocketMQDataBridgeExecute(); |
| 79 | 72 | |
| 80 | 73 | // 2. 创建共享的配置 |
| 81 | - IotDataBridgeDO.RocketMQConfig config = new IotDataBridgeDO.RocketMQConfig(); | |
| 74 | + IotDataBridgeRocketMQConfig config = new IotDataBridgeRocketMQConfig(); | |
| 82 | 75 | config.setNameServer("127.0.0.1:9876"); |
| 83 | 76 | config.setGroup("test-group"); |
| 84 | 77 | config.setTopic("test-topic"); |
| ... | ... | @@ -99,10 +92,10 @@ public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExe |
| 99 | 92 | |
| 100 | 93 | // 4. 执行两次测试,验证缓存 |
| 101 | 94 | log.info("[main][第一次执行,应该会创建新的 producer]"); |
| 102 | - action.executeRocketMQ(message, config); | |
| 95 | + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); | |
| 103 | 96 | |
| 104 | 97 | log.info("[main][第二次执行,应该会复用缓存的 producer]"); |
| 105 | - action.executeRocketMQ(message, config); | |
| 98 | + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); | |
| 106 | 99 | } |
| 107 | 100 | |
| 108 | 101 | } | ... | ... |
yudao-server/pom.xml
| ... | ... | @@ -114,6 +114,19 @@ |
| 114 | 114 | <artifactId>yudao-module-iot-biz</artifactId> |
| 115 | 115 | <version>${revision}</version> |
| 116 | 116 | </dependency> |
| 117 | + <!-- IoT 数据桥梁的执行器所需消息队列。如果您只需要使用 rocketmq 那么则注释掉其它消息队列即可 --> | |
| 118 | + <dependency> | |
| 119 | + <groupId>org.apache.rocketmq</groupId> | |
| 120 | + <artifactId>rocketmq-spring-boot-starter</artifactId> | |
| 121 | + </dependency> | |
| 122 | + <dependency> | |
| 123 | + <groupId>org.springframework.kafka</groupId> | |
| 124 | + <artifactId>spring-kafka</artifactId> | |
| 125 | + </dependency> | |
| 126 | + <dependency> | |
| 127 | + <groupId>org.springframework.boot</groupId> | |
| 128 | + <artifactId>spring-boot-starter-amqp</artifactId> | |
| 129 | + </dependency> | |
| 117 | 130 | |
| 118 | 131 | <!-- spring boot 配置所需依赖 --> |
| 119 | 132 | <dependency> | ... | ... |