【功能优化】Bpm:设备日志的展示

This commit is contained in:
YunaiV 2025-01-28 08:35:07 +08:00
parent 5fbfe49305
commit 6071afeae8
9 changed files with 69 additions and 73 deletions

View File

@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.iot.controller.admin.device;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotTimeDataRespVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -30,8 +30,6 @@ public class IotDeviceDataController {
@Resource @Resource
private IotDevicePropertyService deviceDataService; private IotDevicePropertyService deviceDataService;
@Resource
private IotDeviceLogService deviceLogDataService;
// TODO @浩浩这里的 /latest-list包括方法名 // TODO @浩浩这里的 /latest-list包括方法名
@GetMapping("/latest") @GetMapping("/latest")
@ -49,12 +47,4 @@ public class IotDeviceDataController {
return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); return success(BeanUtils.toBean(list, IotTimeDataRespVO.class));
} }
// TODO:功能权限
@GetMapping("/log/page")
@Operation(summary = "获得设备日志分页")
public CommonResult<PageResult<IotDeviceLogRespVO>> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) {
PageResult<IotDeviceLogDO> pageResult = deviceLogDataService.getDeviceLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class));
}
} }

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.iot.controller.admin.device;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogRespVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - IoT 设备日志")
@RestController
@RequestMapping("/iot/device/log")
@Validated
public class IotDeviceLogController {
@Resource
private IotDeviceLogService deviceLogService;
// TODO:功能权限
@GetMapping("/page")
@Operation(summary = "获得设备日志分页")
public CommonResult<PageResult<IotDeviceLogRespVO>> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) {
PageResult<IotDeviceLogDO> pageResult = deviceLogService.getDeviceLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class));
}
}

View File

@ -4,11 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - IoT 设备日志分页查询 Request VO") @Schema(description = "管理后台 - IoT 设备日志分页查询 Request VO")
@Data @Data
@ -18,16 +13,10 @@ public class IotDeviceLogPageReqVO extends PageParam {
@NotEmpty(message = "设备标识不能为空") @NotEmpty(message = "设备标识不能为空")
private String deviceKey; private String deviceKey;
// TODO @super对应的枚举类
@Schema(description = "消息类型", example = "property") @Schema(description = "消息类型", example = "property")
private String type; private String type; // 参见 IotDeviceMessageTypeEnum 枚举精准匹配
@Schema(description = "标识符", example = "temperature") @Schema(description = "标识符", example = "temperature")
// TODO @super对应的枚举类 private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举模糊匹配
private String subType;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
} }

View File

@ -4,18 +4,17 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDevi
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List;
/** /**
* 设备日志 {@link IotDeviceLogDO} Mapper 接口 * 设备日志 {@link IotDeviceLogDO} Mapper 接口
*/ */
@Mapper @Mapper
@TDengineDS @TDengineDS
@InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析因为 JSqlParser TDengine SQL 解析会报错 @InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析因为 JSqlParser TDengine SQL 解析会报错
public interface IotDeviceLogDataMapper { public interface IotDeviceLogMapper {
/** /**
* 创建设备日志超级表 * 创建设备日志超级表
@ -44,7 +43,8 @@ public interface IotDeviceLogDataMapper {
* @param reqVO 分页查询条件 * @param reqVO 分页查询条件
* @return 设备日志列表 * @return 设备日志列表
*/ */
List<IotDeviceLogDO> selectPage(@Param("reqVO") IotDeviceLogPageReqVO reqVO); IPage<IotDeviceLogDO> selectPage(IPage<IotDeviceLogDO> page,
@Param("reqVO") IotDeviceLogPageReqVO reqVO);
/** /**
* 获得设备日志总数 * 获得设备日志总数

View File

@ -20,7 +20,7 @@ import java.util.stream.Collectors;
@Mapper @Mapper
@TDengineDS @TDengineDS
@InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析因为 JSqlParser TDengine SQL 解析会报错 @InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析因为 JSqlParser TDengine SQL 解析会报错
public interface IotDevicePropertyDataMapper { public interface IotDevicePropertyMapper {
List<TDengineTableField> getProductPropertySTableFieldList(@Param("productKey") String productKey); List<TDengineTableField> getProductPropertySTableFieldList(@Param("productKey") String productKey);

View File

@ -7,15 +7,15 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.util.List;
/** /**
* IoT 设备日志数据 Service 实现类 * IoT 设备日志数据 Service 实现类
* *
@ -27,17 +27,17 @@ import java.util.List;
public class IotDeviceLogServiceImpl implements IotDeviceLogService { public class IotDeviceLogServiceImpl implements IotDeviceLogService {
@Resource @Resource
private IotDeviceLogDataMapper deviceLogDataMapper; private IotDeviceLogMapper deviceLogMapper;
@Override @Override
public void defineDeviceLog() { public void defineDeviceLog() {
if (StrUtil.isNotEmpty(deviceLogDataMapper.showDeviceLogSTable())) { if (StrUtil.isNotEmpty(deviceLogMapper.showDeviceLogSTable())) {
log.info("[defineDeviceLog][设备日志超级表已存在,创建跳过]"); log.info("[defineDeviceLog][设备日志超级表已存在,创建跳过]");
return; return;
} }
log.info("[defineDeviceLog][设备日志超级表不存在,创建开始...]"); log.info("[defineDeviceLog][设备日志超级表不存在,创建开始...]");
deviceLogDataMapper.createDeviceLogSTable(); deviceLogMapper.createDeviceLogSTable();
log.info("[defineDeviceLog][设备日志超级表不存在,创建成功]"); log.info("[defineDeviceLog][设备日志超级表不存在,创建成功]");
} }
@ -46,15 +46,15 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService {
IotDeviceLogDO log = BeanUtils.toBean(message, IotDeviceLogDO.class) IotDeviceLogDO log = BeanUtils.toBean(message, IotDeviceLogDO.class)
.setId(IdUtil.fastSimpleUUID()) .setId(IdUtil.fastSimpleUUID())
.setContent(JsonUtils.toJsonString(message.getData())); .setContent(JsonUtils.toJsonString(message.getData()));
deviceLogDataMapper.insert(log); deviceLogMapper.insert(log);
} }
@Override @Override
public PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { public PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) {
// TODO @芋艿增加一个表不存在的 try catch // TODO @芋艿增加一个表不存在的 try catch
List<IotDeviceLogDO> list = deviceLogDataMapper.selectPage(pageReqVO); IPage<IotDeviceLogDO> page = deviceLogMapper.selectPage(
Long total = deviceLogDataMapper.selectCount(pageReqVO); new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO);
return new PageResult<>(list, total); return new PageResult<>(page.getRecords(), page.getTotal());
} }
} }

View File

@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO; import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO;
import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyMapper;
import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum;
import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;
import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField;
@ -68,7 +68,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
private DevicePropertyRedisDAO deviceDataRedisDAO; private DevicePropertyRedisDAO deviceDataRedisDAO;
@Resource @Resource
private IotDevicePropertyDataMapper devicePropertyDataMapper; private IotDevicePropertyMapper devicePropertyMapper;
@Override @Override
public void defineDevicePropertyData(Long productId) { public void defineDevicePropertyData(Long productId) {
@ -79,7 +79,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
// 1.2 解析 DB 里的字段 // 1.2 解析 DB 里的字段
List<TDengineTableField> oldFields = new ArrayList<>(); List<TDengineTableField> oldFields = new ArrayList<>();
try { try {
oldFields.addAll(devicePropertyDataMapper.getProductPropertySTableFieldList(product.getProductKey())); oldFields.addAll(devicePropertyMapper.getProductPropertySTableFieldList(product.getProductKey()));
} catch (Exception e) { } catch (Exception e) {
if (!e.getMessage().contains("Table does not exist")) { if (!e.getMessage().contains("Table does not exist")) {
throw e; throw e;
@ -93,11 +93,11 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
log.info("[defineDevicePropertyData][productId({}) 没有需要定义的属性]", productId); log.info("[defineDevicePropertyData][productId({}) 没有需要定义的属性]", productId);
return; return;
} }
devicePropertyDataMapper.createProductPropertySTable(product.getProductKey(), newFields); devicePropertyMapper.createProductPropertySTable(product.getProductKey(), newFields);
return; return;
} }
// 2.2 情况二如果是修改的时候需要更新表 // 2.2 情况二如果是修改的时候需要更新表
devicePropertyDataMapper.alterProductPropertySTable(product.getProductKey(), oldFields, newFields); devicePropertyMapper.alterProductPropertySTable(product.getProductKey(), oldFields, newFields);
} }
private List<TDengineTableField> buildTableFieldList(List<IotThingModelDO> thingModels) { private List<TDengineTableField> buildTableFieldList(List<IotThingModelDO> thingModels) {
@ -142,7 +142,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
} }
// 3.1 保存设备属性数据 // 3.1 保存设备属性数据
devicePropertyDataMapper.insert(device, properties, devicePropertyMapper.insert(device, properties,
LocalDateTimeUtil.toEpochMilli(message.getReportTime())); // TODO @芋艿后续要看看查询的时候能不能用 LocalDateTime LocalDateTimeUtil.toEpochMilli(message.getReportTime())); // TODO @芋艿后续要看看查询的时候能不能用 LocalDateTime
// 3.2 保存设备属性日志 // 3.2 保存设备属性日志

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper <!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper"> <mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper">
<update id="createDeviceLogSTable"> <update id="createDeviceLogSTable">
CREATE STABLE IF NOT EXISTS device_log ( CREATE STABLE IF NOT EXISTS device_log (
@ -40,38 +40,17 @@
</insert> </insert>
<select id="selectPage" resultType="cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO"> <select id="selectPage" resultType="cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO">
SELECT ts, id, device_key, product_key, type, sub_type, content, report_time SELECT ts, id, device_key, product_key, type, identifier, content, report_time
FROM device_log_${reqVO.deviceKey} FROM device_log_${reqVO.deviceKey}
<where> <where>
<if test="reqVO.type != null and reqVO.type != ''"> <if test="reqVO.type != null and reqVO.type != ''">
AND type = #{reqVO.type} AND type = #{reqVO.type}
</if> </if>
<if test="reqVO.subType != null and reqVO.subType != ''"> <if test="reqVO.identifier != null and reqVO.identifier != ''">
AND subType = #{reqVO.subType} AND identifier LIKE CONCAT('%',#{reqVO.identifier},'%')
</if>
<if test="reqVO.createTime != null">
AND ts BETWEEN #{reqVO.createTime[0]} AND #{reqVO.createTime[1]}
</if> </if>
</where> </where>
ORDER BY ts DESC ORDER BY ts DESC
LIMIT #{reqVO.pageSize} OFFSET #{reqVO.pageNo}
</select>
<!-- TODO 芋艿:看看能不能复用 mybatis-plus 的 selectCount 方法 -->
<select id="selectCount" resultType="Long">
SELECT COUNT(*)
FROM device_log_${reqVO.deviceKey}
<where>
<if test="reqVO.type != null and reqVO.type != ''">
AND type = #{reqVO.type}
</if>
<if test="reqVO.subType != null and reqVO.subType != ''">
AND subType = #{reqVO.subType}
</if>
<if test="reqVO.createTime != null">
AND ts BETWEEN #{reqVO.createTime[0]} AND #{reqVO.createTime[1]}
</if>
</where>
</select> </select>
</mapper> </mapper>

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper <!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper"> <mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyMapper">
<select id="getProductPropertySTableFieldList" resultType="cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField"> <select id="getProductPropertySTableFieldList" resultType="cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField">
DESCRIBE product_property_${productKey} DESCRIBE product_property_${productKey}