feat: 新功能开发,监测历史记录。微信和物联网平台,模块搭建。

This commit is contained in:
tianyongbao
2025-11-05 00:35:23 +08:00
parent 1d2e2e2513
commit 05fb822744
38 changed files with 2099 additions and 49 deletions

View File

@@ -102,11 +102,6 @@
<groupId>com.intc</groupId>
<artifactId>intc-common-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>2.0.40</version>
</dependency>
</dependencies>
</project>

View File

@@ -27,8 +27,11 @@ public class DeviceSensorDataController extends BaseController
private IDeviceSensorDataService deviceSensorDataService;
@GetMapping("/getHistoryData")
public List<DeviceSensorData> getHistoryData(@RequestParam("serialNum") String serialNum, @RequestParam("deviceId") Long deviceId, @RequestParam("mobilePhone") String mobilePhone, @RequestParam("deviceType") int deviceType, @RequestParam("startTime") String startTime, @RequestParam("endTime") String endTime)
public List<DeviceSensorData> getHistoryData(@RequestParam("serialNum") String serialNum,
@RequestParam("startTime") String startTime,
@RequestParam("endTime") String endTime,
@RequestParam(value = "intervalType", required = false, defaultValue = "1") Integer intervalType)
{
return deviceSensorDataService.getHistoryDataList(serialNum,deviceId,mobilePhone,deviceType,startTime,endTime);
return deviceSensorDataService.getHistoryDataList(serialNum, startTime, endTime, intervalType);
}
}

View File

@@ -1,8 +1,12 @@
package com.intc.tdengine.domain;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor // 生成无参构造方法
@@ -10,17 +14,64 @@ import java.time.LocalDateTime;
public class DeviceSensorData {
// 测量字段(随时间变化的数值)
private LocalDateTime time; // 时序主键时间戳
private LocalDateTime createTime; // 数据创建时间
private double dissolvedOxygen; // 溶解氧
private double temperature; // 温度
private double saturability; // 饱和度
private double ph; // pH值
private double salinity; // 盐度
private double treference; // 参考值(具体含义需结合业务)
private double tfluorescence; // 荧光值
private double phaseDifference; // 相位差
private double battery; // 电池电量
private String time; // 时序主键时间戳
private String createTime; // 数据创建时间
private Double dissolvedOxygen; // 溶解氧
private Double temperature; // 温度
private Double saturability; // 饱和度
private Double ph; // pH值
private Double salinity; // 盐度
private Double treference; // 参考值(具体含义需结合业务)
private Double tfluorescence; // 荧光值
private Double phaseDifference; // 相位差
private Double battery; // 电池电量
// Getter 方法,返回保留两位小数的值
public Double getDissolvedOxygen() {
return roundToTwoDecimals(dissolvedOxygen);
}
public Double getTemperature() {
return roundToTwoDecimals(temperature);
}
public Double getSaturability() {
return roundToTwoDecimals(saturability);
}
public Double getPh() {
return roundToTwoDecimals(ph);
}
public Double getSalinity() {
return roundToTwoDecimals(salinity);
}
public Double getTreference() {
return roundToTwoDecimals(treference);
}
public Double getTfluorescence() {
return roundToTwoDecimals(tfluorescence);
}
public Double getPhaseDifference() {
return roundToTwoDecimals(phaseDifference);
}
public Double getBattery() {
return roundToTwoDecimals(battery);
}
// 工具方法:保留两位小数
private Double roundToTwoDecimals(Double value) {
if (value == null) {
return null;
}
return BigDecimal.valueOf(value)
.setScale(2, RoundingMode.HALF_UP)
.doubleValue();
}
// 标签字段(元数据,不随时间频繁变化)
private String serialNum; // 设备序列号

View File

@@ -1,5 +1,7 @@
package com.intc.tdengine.mapper;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.intc.tdengine.domain.DeviceSensorData;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -8,7 +10,6 @@ import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
@Mapper
public interface DeviceSensorDataMapper {
/**
@@ -46,13 +47,24 @@ public interface DeviceSensorDataMapper {
* @param dataList 数据列表
* @return 影响行数
*/
@DS("taos")
@InterceptorIgnore(tenantLine = "true")
int batchInsertDeviceSensorData(@Param("dataList") List<DeviceSensorData> dataList);
/**
* 查询数据
*
* @return 影响行数
* @param serialNum 设备序列号
* @param startTime 开始时间
* @param endTime 结束时间
* @param intervalType 间隔类型1-原始数据2-10分钟3-30分钟4-1小时5-3小时6-6小时
* @return 设备传感器数据列表
*/
List<DeviceSensorData> getHistoryDataList(@Param("serialNum") String serialNum,@Param("deviceId") Long deviceId,@Param("mobilePhone") String mobilePhone,@Param("deviceType") int deviceType,@Param("startTime") String startTime,@Param("endTime") String endTime);
@DS("taos")
@InterceptorIgnore(tenantLine = "true")
List<DeviceSensorData> getHistoryDataList(@Param("serialNum") String serialNum,
@Param("startTime") String startTime,
@Param("endTime") String endTime,
@Param("intervalType") Integer intervalType);
}

View File

@@ -29,9 +29,13 @@ public interface IDeviceSensorDataService {
public void batchInsertDeviceSensorData(List<DeviceSensorData> dataList);
/**
* 查询数据
* 查询历史数据列表
*
* @return 影响行数
* @param serialNum 设备序列号
* @param startTime 开始时间
* @param endTime 结束时间
* @param intervalType 间隔类型1-原始数据2-10分钟3-30分钟4-1小时5-3小时6-6小时
* @return 设备传感器数据列表
*/
public List<DeviceSensorData> getHistoryDataList(String serialNum, Long deviceId, String mobilePhone, int deviceType, String startTime, String endTime);
public List<DeviceSensorData> getHistoryDataList(String serialNum, String startTime, String endTime, Integer intervalType);
}

View File

@@ -1,14 +1,19 @@
package com.intc.tdengine.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.intc.tdengine.domain.DeviceSensorData;
import com.intc.tdengine.mapper.DeviceSensorDataMapper;
import com.intc.tdengine.service.IDeviceSensorDataService;
import jakarta.annotation.Resource;
import org.apache.ibatis.annotations.Param;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
@DS("taos") // 指定使用 taos 数据源TDengine
public class DeviceSensorDataService implements IDeviceSensorDataService {
@Resource
private DeviceSensorDataMapper deviceSensorDataMapper;
@@ -37,18 +42,69 @@ public class DeviceSensorDataService implements IDeviceSensorDataService {
}
/**
* 查询数据
* 查询历史数据列表
*
* @return 影响行数
* @param serialNum 设备序列号
* @param startTime 开始时间
* @param endTime 结束时间
* @param intervalType 间隔类型1-原始数据2-10分钟3-30分钟4-1小时5-3小时6-6小时
* @return 设备传感器数据列表
*/
@Override
public List<DeviceSensorData> getHistoryDataList(String serialNum,Long deviceId, String mobilePhone, int deviceType,String startTime, String endTime) {
List<DeviceSensorData> list=new ArrayList<>();
public List<DeviceSensorData> getHistoryDataList(String serialNum, String startTime, String endTime, Integer intervalType) {
List<DeviceSensorData> list = new ArrayList<>();
try {
list=deviceSensorDataMapper.getHistoryDataList(serialNum,deviceId,mobilePhone,deviceType,startTime,endTime);
}catch (Exception e){
// 默认为原始数据
if (intervalType == null) {
intervalType = 1;
}
// 验证intervalType参数
if (intervalType < 1 || intervalType > 6) {
log.error("无效的intervalType参数: {}, 使用默认值1", intervalType);
intervalType = 1;
}
// 处理时间格式
if (startTime != null && !startTime.contains(" ")) {
startTime = startTime + " 00:00:00";
}
if (endTime != null && !endTime.contains(" ")) {
endTime = endTime + " 23:59:59";
}
String intervalDesc = getIntervalDesc(intervalType);
log.info("查询TDengine历史数据: serialNum={}, startTime={}, endTime={}, intervalType={} ({})",
serialNum, startTime, endTime, intervalType, intervalDesc);
list = deviceSensorDataMapper.getHistoryDataList(serialNum, startTime, endTime, intervalType);
log.info("查询到 {} 条历史数据 ({})", list.size(), intervalDesc);
} catch (Exception e) {
log.error("查询TDengine历史数据失败", e);
// 打印完整异常链
Throwable cause = e;
int level = 0;
while (cause != null && level < 10) {
log.error("异常层级 {}: {}", level++, cause.getClass().getName() + ": " + cause.getMessage());
cause = cause.getCause();
}
}
return list;
}
/**
* 获取间隔类型描述
*/
private String getIntervalDesc(Integer intervalType) {
switch (intervalType) {
case 1: return "原始数据";
case 2: return "10分钟间隔";
case 3: return "30分钟间隔";
case 4: return "1小时间隔";
case 5: return "3小时间隔";
case 6: return "6小时间隔";
default: return "未知";
}
}
}

View File

@@ -52,14 +52,57 @@
</foreach>
</insert>
<select id="getHistoryDataList" parameterType="String" resultType="com.intc.tdengine.domain.DeviceSensorData">
select time,createTime,dissolvedOxygen,temperature,saturability,ph,salinity,treference,tfluorescence,phaseDifference,battery,serialNum,deviceId,data.mobilePhone,deviceType from fishery.t_#{serialNum}
<where>
time >= #{startTime} and time &lt;= #{endTime}
<if test="serialNum != null and serialNum != ''"> AND serialNum=#{serialNum}</if>
<if test="deviceId != null "> AND deviceId=#{deviceId}</if>
<if test="mobilePhone != null and mobilePhone != ''"> AND mobilePhone=#{mobilePhone}</if>
<if test="deviceType != null"> AND deviceType=#{deviceType}</if>
</where>
<select id="getHistoryDataList" resultType="com.intc.tdengine.domain.DeviceSensorData">
<if test="intervalType == null or intervalType == 1">
<!-- 原始数据,不聚合 -->
SELECT
`time`,
createTime,
dissolvedOxygen,
temperature,
saturability,
ph,
salinity,
treference,
tfluorescence,
phaseDifference,
battery,
serialNum,
deviceId,
mobilePhone,
deviceType
FROM `fishery`.`t_${serialNum}`
<where>
<if test="startTime != null and startTime != ''">AND `time` >= #{startTime}</if>
<if test="endTime != null and endTime != ''">AND `time` &lt;= #{endTime}</if>
</where>
</if>
<if test="intervalType != null and intervalType != 1">
<!-- 按时间间隔聚合 -->
SELECT
_wstart as `time`,
_wstart as createTime,
AVG(dissolvedOxygen) as dissolvedOxygen,
AVG(temperature) as temperature,
AVG(saturability) as saturability,
AVG(ph) as ph,
AVG(salinity) as salinity,
AVG(treference) as treference,
AVG(tfluorescence) as tfluorescence,
AVG(phaseDifference) as phaseDifference,
AVG(battery) as battery
FROM `fishery`.`t_${serialNum}`
<where>
<if test="startTime != null and startTime != ''">AND `time` >= #{startTime}</if>
<if test="endTime != null and endTime != ''">AND `time` &lt;= #{endTime}</if>
</where>
<choose>
<when test="intervalType == 2">INTERVAL(10m)</when>
<when test="intervalType == 3">INTERVAL(30m)</when>
<when test="intervalType == 4">INTERVAL(1h)</when>
<when test="intervalType == 5">INTERVAL(3h)</when>
<when test="intervalType == 6">INTERVAL(6h)</when>
</choose>
</if>
</select>
</mapper>