【代码优化】IoT:重构设备 upstream 为 message,包括上行 + 下行

This commit is contained in:
YunaiV 2025-01-30 08:43:41 +08:00
parent 5110948db8
commit 2f1598a5da
12 changed files with 147 additions and 59 deletions

View File

@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService;
import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceUpstreamService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

View File

@ -7,8 +7,11 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceSimulationUpstreamReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceDownstreamService;
import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceUpstreamService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -37,6 +40,10 @@ public class IotDeviceController {
@Resource
private IotDeviceService deviceService;
@Resource
private IotDeviceUpstreamService deviceUpstreamService;
@Resource
private IotDeviceDownstreamService deviceDownstreamService;
@PostMapping("/create")
@Operation(summary = "创建设备")
@ -151,11 +158,21 @@ public class IotDeviceController {
ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list);
}
@PostMapping("/simulation-report")
@Operation(summary = "模拟设备上报")
@PreAuthorize("@ss.hasPermission('iot:device:simulation-report')")
public CommonResult<Boolean> simulationReportDevice(@Valid @RequestBody IotDeviceSimulationReportReqVO simulatorReqVO) {
deviceService.simulationReportDevice(simulatorReqVO);
@PostMapping("/simulation-upstream")
@Operation(summary = "模拟设备上行")
@PreAuthorize("@ss.hasPermission('iot:device:simulation')")
public CommonResult<Boolean> simulationDeviceUpstream(
@Valid @RequestBody IotDeviceSimulationUpstreamReqVO upstreamReqVO) {
deviceUpstreamService.simulationDeviceUpstream(upstreamReqVO);
return success(true);
}
@PostMapping("/simulation-downstream")
@Operation(summary = "模拟设备下行")
@PreAuthorize("@ss.hasPermission('iot:device:simulation')")
public CommonResult<Boolean> simulationDownstreamDevice(
@Valid @RequestBody IotDeviceSimulationUpstreamReqVO downstreamReqVO) {
deviceDownstreamService.simulationDeviceDownstream(downstreamReqVO);
return success(true);
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - IoT 模拟设备下行 Request VO") // 服务调用属性设置属性获取等
@Data
public class IotDeviceSimulationDownstreamReqVO {
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
@NotNull(message = "设备编号不能为空")
private Long id;
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
@NotEmpty(message = "消息类型不能为空")
@InEnum(IotDeviceMessageTypeEnum.class)
private String type;
@Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
@NotEmpty(message = "标识符不能为空")
private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
@Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
private Object data; // 例如说服务调用的 params属性设置的 properties
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
@ -7,9 +7,9 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - IoT 模拟设备上 Request VO") // 属性上报事件上报状态变更等
@Schema(description = "管理后台 - IoT 模拟设备上 Request VO") // 属性上报事件上报状态变更等
@Data
public class IotDeviceSimulationReportReqVO {
public class IotDeviceSimulationUpstreamReqVO {
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
@NotNull(message = "设备编号不能为空")

View File

@ -10,7 +10,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService;
import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceUpstreamService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

View File

@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService;
import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceUpstreamService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;

View File

@ -144,11 +144,4 @@ public interface IotDeviceService {
*/
IotDeviceImportRespVO importDevice(List<IotDeviceImportExcelVO> importDevices, boolean updateSupport);
/**
* 模拟设备上报
*
* @param reportReqVO 上报信息
*/
void simulationReportDevice(IotDeviceSimulationReportReqVO reportReqVO);
}

View File

@ -10,18 +10,14 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService;
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
import jakarta.annotation.Resource;
import jakarta.validation.ConstraintViolationException;
@ -59,9 +55,6 @@ public class IotDeviceServiceImpl implements IotDeviceService {
@Resource
@Lazy // 延迟加载解决循环依赖
private IotDeviceGroupService deviceGroupService;
@Resource
@Lazy // 延迟加载解决循环依赖
private IotDeviceUpstreamService deviceUpstreamService;
@Override
public Long createDevice(IotDeviceSaveReqVO createReqVO) {
@ -395,38 +388,6 @@ public class IotDeviceServiceImpl implements IotDeviceService {
return respVO;
}
// TODO @芋艿要不改成 simulationUpstream原因里面不只有上报还有更新状态那么 upstream 更适合
@Override
@SuppressWarnings("unchecked")
public void simulationReportDevice(IotDeviceSimulationReportReqVO reportReqVO) {
// 1. 校验存在
IotDeviceDO device = validateDeviceExists(reportReqVO.getId());
// 2.1 情况一属性上报
String requestId = IdUtil.fastSimpleUUID();
if (Objects.equals(reportReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) {
deviceUpstreamService.reportDeviceProperty(((IotDevicePropertyReportReqDTO)
new IotDevicePropertyReportReqDTO().setRequestId(requestId).setReportTime(LocalDateTime.now())
.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName()))
.setProperties((Map<String, Object>) reportReqVO.getData()));
return;
}
// 2.2 情况二事件上报
if (Objects.equals(reportReqVO.getType(), IotDeviceMessageTypeEnum.EVENT.getType())) {
// TODO 芋艿待实现
return;
}
// 2.3 情况三状态变更
if (Objects.equals(reportReqVO.getType(), IotDeviceMessageTypeEnum.STATE.getType())) {
deviceUpstreamService.updateDeviceState(((IotDeviceStateUpdateReqDTO)
new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()).setReportTime(LocalDateTime.now())
.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName()))
.setState((Integer) reportReqVO.getData()));
return;
}
throw new IllegalArgumentException("未知的类型:" + reportReqVO.getType());
}
private void deleteDeviceCache(IotDeviceDO device) {
// 保证在 @CacheEvict 之前忽略租户
TenantUtils.executeIgnore(() -> getSelf().deleteDeviceCache0(device));

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.iot.service.device.message;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceSimulationUpstreamReqVO;
import jakarta.validation.Valid;
/**
* 设备下行 Service 接口
*
* 目的服务端 -> 插件 -> 设备
*
* @author 芋道源码
*/
public interface IotDeviceDownstreamService {
/**
* 模拟设备下行
*
* @param downstreamReqVO 设备下行请求 VO
*/
void simulationDeviceDownstream(@Valid IotDeviceSimulationUpstreamReqVO downstreamReqVO);
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.iot.service.device.message;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceSimulationUpstreamReqVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
/**
* 设备下行 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
@Slf4j
public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamService {
@Override
public void simulationDeviceDownstream(IotDeviceSimulationUpstreamReqVO downstreamReqVO) {
}
}

View File

@ -1,8 +1,10 @@
package cn.iocoder.yudao.module.iot.service.device.upstream;
package cn.iocoder.yudao.module.iot.service.device.message;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceSimulationUpstreamReqVO;
import jakarta.validation.Valid;
/**
* 设备上行 Service 接口
@ -13,6 +15,13 @@ import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
*/
public interface IotDeviceUpstreamService {
/**
* 模拟设备上行
*
* @param simulatorReqVO 设备上行请求 VO
*/
void simulationDeviceUpstream(@Valid IotDeviceSimulationUpstreamReqVO simulatorReqVO);
/**
* 更新设备状态
*

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.iot.service.device.upstream;
package cn.iocoder.yudao.module.iot.service.device.message;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceUpstreamAbstractReqDTO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceSimulationUpstreamReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
@ -25,6 +26,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
/**
@ -45,6 +47,37 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
@Resource
private IotDeviceProducer deviceProducer;
@Override
@SuppressWarnings("unchecked")
public void simulationDeviceUpstream(IotDeviceSimulationUpstreamReqVO simulatorReqVO) {
// 1. 校验存在
IotDeviceDO device = deviceService.validateDeviceExists(simulatorReqVO.getId());
// 2.1 情况一属性上报
String requestId = IdUtil.fastSimpleUUID();
if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) {
reportDeviceProperty(((IotDevicePropertyReportReqDTO)
new IotDevicePropertyReportReqDTO().setRequestId(requestId).setReportTime(LocalDateTime.now())
.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName()))
.setProperties((Map<String, Object>) simulatorReqVO.getData()));
return;
}
// 2.2 情况二事件上报
if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.EVENT.getType())) {
// TODO 芋艿待实现
return;
}
// 2.3 情况三状态变更
if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.STATE.getType())) {
updateDeviceState(((IotDeviceStateUpdateReqDTO)
new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()).setReportTime(LocalDateTime.now())
.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName()))
.setState((Integer) simulatorReqVO.getData()));
return;
}
throw new IllegalArgumentException("未知的类型:" + simulatorReqVO.getType());
}
@Override
public void updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
Assert.isTrue(ObjectUtils.equalsAny(updateReqDTO.getState(),