xiepufeng
9 months ago
13 changed files with 1151 additions and 25 deletions
@ -0,0 +1,144 @@ |
|||
package com.zc.business.domain; |
|||
|
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import com.ruoyi.common.core.domain.BaseEntity; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import lombok.Data; |
|||
import org.apache.commons.codec.digest.DigestUtils; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Objects; |
|||
|
|||
/** |
|||
* 交通断面数据统计定义 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Data |
|||
public class DcTrafficSectionData extends BaseEntity { |
|||
|
|||
/** |
|||
* 主键 |
|||
*/ |
|||
@TableId |
|||
private String id; |
|||
|
|||
/** |
|||
* 车流量 |
|||
*/ |
|||
private Integer trafficVolume; |
|||
|
|||
/** |
|||
* 平均速度 |
|||
*/ |
|||
private Integer averageSpeed; |
|||
|
|||
/** |
|||
* 所属设备 |
|||
*/ |
|||
private Long deviceId; |
|||
|
|||
/** |
|||
* 统计时间 |
|||
*/ |
|||
private Date statisticalDate; |
|||
|
|||
/** |
|||
* 道路方向 |
|||
*/ |
|||
private Byte direction; |
|||
|
|||
/** |
|||
* 时段类型 |
|||
* 1-年 2-月 3-季 4-日 |
|||
*/ |
|||
private Byte periodType; |
|||
|
|||
|
|||
/** |
|||
* 所在桩号 |
|||
*/ |
|||
private Integer stakeMark; |
|||
|
|||
/** |
|||
* 设置交通数据的统计周期类型。 |
|||
* @param periodType 统计周期类型的枚举值。 |
|||
*/ |
|||
public void setPeriodType(TrafficDataPeriodTypeEnum periodType) { |
|||
this.periodType = periodType.getCode(); // 将枚举类型转换为代码值存储
|
|||
} |
|||
|
|||
|
|||
/** |
|||
* 重写equals方法,用于比较两个对象是否相等。 |
|||
* @param o 要与当前对象比较的对象。 |
|||
* @return 如果两个对象相等,则返回true;否则返回false。 |
|||
*/ |
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) return true; // 同一对象比较,直接返回true
|
|||
if (o == null || getClass() != o.getClass()) return false; // 对象为空或类型不同,返回false
|
|||
DcTrafficSectionData that = (DcTrafficSectionData) o; // 类型转换
|
|||
return Objects.equals(deviceId, that.deviceId) && |
|||
Objects.equals(statisticalDate, that.statisticalDate) && |
|||
Objects.equals(direction, that.direction) && |
|||
Objects.equals(periodType, that.periodType) && |
|||
Objects.equals(stakeMark, that.stakeMark); // 比较各属性值
|
|||
} |
|||
|
|||
/** |
|||
* 重写hashCode方法,基于对象的属性生成哈希码。 |
|||
* @return 对象的哈希码值。 |
|||
*/ |
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(deviceId, statisticalDate, direction, periodType, stakeMark); |
|||
} |
|||
|
|||
/** |
|||
* 设置统计日期,根据不同的统计周期类型来调整日期,使其对应周期的起始日期。 |
|||
* @param statisticalDate 统计日期,原始日期。 |
|||
*/ |
|||
public void setStatisticalDate(Date statisticalDate) { |
|||
TrafficDataPeriodTypeEnum typeEnum = TrafficDataPeriodTypeEnum.valueOfCode(periodType); |
|||
setStatisticalDate(statisticalDate, typeEnum); |
|||
} |
|||
|
|||
/** |
|||
* 根据给定的统计周期类型和日期,设置统计日期为相应周期的起始日期。 |
|||
* @param statisticalDate 原始统计日期。 |
|||
* @param typeEnum 统计周期类型。 |
|||
*/ |
|||
public void setStatisticalDate(Date statisticalDate, TrafficDataPeriodTypeEnum typeEnum) { |
|||
switch (typeEnum) { |
|||
case DAY: |
|||
// 设置为当天的起始时间
|
|||
this.statisticalDate = DateUtil.beginOfDay(statisticalDate); |
|||
break; |
|||
case MONTH: |
|||
// 设置为当月的起始日期
|
|||
this.statisticalDate = DateUtil.beginOfMonth(statisticalDate); |
|||
break; |
|||
case QUARTER: |
|||
// 设置为当季度的起始日期
|
|||
this.statisticalDate = DateUtil.beginOfQuarter(statisticalDate); |
|||
break; |
|||
case YEAR: |
|||
// 设置为当年的起始日期
|
|||
this.statisticalDate = DateUtil.beginOfYear(statisticalDate); |
|||
break; |
|||
default: |
|||
// 如果不是预定义的周期类型,则不做任何处理
|
|||
this.statisticalDate = statisticalDate; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 根据设备ID、统计时间、方向、时段类型、桩号生成一个唯一ID |
|||
*/ |
|||
public void generateUniqueId() { |
|||
String combinedAttributes = deviceId + "_" + DateUtil.format(statisticalDate, "yyyyMMdd_HHmmss") + "_" + direction + "_" + periodType + "_" + stakeMark; |
|||
this.id = DigestUtils.md5Hex(combinedAttributes); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,49 @@ |
|||
package com.zc.business.enums; |
|||
|
|||
import lombok.Getter; |
|||
|
|||
/** |
|||
* 定义一个枚举类型 TrafficDataPeriodTypeEnum,用于表示周期类型(年、月、季、日) |
|||
*/ |
|||
@Getter |
|||
public enum TrafficDataPeriodTypeEnum { |
|||
// 枚举成员:年,关联字节型代码 1 和描述 "年"
|
|||
YEAR((byte) 1, "年"), |
|||
|
|||
// 枚举成员:月,关联字节型代码 2 和描述 "月"
|
|||
MONTH((byte) 2, "月"), |
|||
|
|||
// 枚举成员:季,关联字节型代码 3 和描述 "季"
|
|||
QUARTER((byte) 3, "季"), |
|||
|
|||
// 枚举成员:日,关联字节型代码 4 和描述 "日"
|
|||
DAY((byte) 4, "日"); |
|||
|
|||
// 每个枚举成员的属性:代码,存储对应的字节型数值
|
|||
private final Byte code; |
|||
|
|||
// 每个枚举成员的属性:描述,存储该周期类型的中文描述
|
|||
private final String description; |
|||
|
|||
// 构造方法,初始化每个枚举成员的代码和描述信息
|
|||
TrafficDataPeriodTypeEnum(Byte code, String description) { |
|||
this.code = code; |
|||
this.description = description; |
|||
} |
|||
|
|||
// 反向查找方法,根据给定的字节型代码查找对应的枚举值
|
|||
// 如果找到匹配项,则返回该枚举类型;否则抛出IllegalArgumentException异常
|
|||
public static TrafficDataPeriodTypeEnum valueOfCode(Byte code) { |
|||
// 遍历所有PeriodTypeEnum枚举值
|
|||
for (TrafficDataPeriodTypeEnum type : values()) { |
|||
// 如果当前枚举类型的code与输入的code相等
|
|||
if (type.getCode().equals(code)) { |
|||
// 返回找到的枚举类型
|
|||
return type; |
|||
} |
|||
} |
|||
|
|||
// 如果循环结束都没有找到匹配的code,则抛出异常,说明提供的code非法
|
|||
throw new IllegalArgumentException("无效的周期类型代码: " + code); |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
package com.zc.business.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
/** |
|||
* 交通断面数据统计Mapper接口 |
|||
* |
|||
* @author xiepufeng |
|||
*/ |
|||
@Mapper |
|||
public interface DcTrafficSectionDataMapper extends BaseMapper<DcTrafficSectionData> { |
|||
|
|||
/** |
|||
* 插入或更新交通路段数据。 |
|||
* |
|||
* @param trafficSectionData 交通路段数据对象,包含需要插入或更新的数据。 |
|||
* @return 返回一个布尔值,表示操作是否成功。true表示插入或更新成功,false表示失败。 |
|||
*/ |
|||
boolean insertOrUpdate(DcTrafficSectionData trafficSectionData); |
|||
} |
@ -0,0 +1,15 @@ |
|||
package com.zc.business.service; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
|
|||
public interface DcTrafficSectionDataService extends IService<DcTrafficSectionData> { |
|||
|
|||
/** |
|||
* 处理实时接收到的设备消息,并将其转换为交通断面统计数据对象并缓存。 |
|||
* |
|||
* @param msg 设备发送的JSON格式实时消息 |
|||
*/ |
|||
void processRealtimeMessage(JSONObject msg); |
|||
} |
@ -0,0 +1,173 @@ |
|||
package com.zc.business.service.impl; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.ruoyi.common.utils.DateUtils; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.statistics.cache.*; |
|||
import com.zc.business.mapper.DcTrafficSectionDataMapper; |
|||
import com.zc.business.service.DcTrafficSectionDataService; |
|||
import com.zc.business.statistics.handler.RealtimeTrafficStatistics; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.annotation.Resource; |
|||
import java.util.Map; |
|||
import java.util.function.Consumer; |
|||
|
|||
/** |
|||
* 通断面数据服务实现类,负责处理实时设备消息、缓存数据、定时任务以及数据保存等功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Service |
|||
public class DcTrafficSectionDataServiceImpl |
|||
extends ServiceImpl<DcTrafficSectionDataMapper, DcTrafficSectionData> |
|||
implements DcTrafficSectionDataService { |
|||
|
|||
@Resource |
|||
private DcTrafficSectionDataMapper dcTrafficSectionDataMapper; |
|||
|
|||
/** |
|||
* 处理实时接收到的设备消息,并将其转换为交通断面统计数据对象并缓存。 |
|||
* |
|||
* @param msg 设备发送的JSON格式实时消息 |
|||
*/ |
|||
@Override |
|||
public void processRealtimeMessage(JSONObject msg) { |
|||
|
|||
// 1. 将设备消息转换为交通断面数据统计定义对象
|
|||
DcTrafficSectionData dcTrafficSectionData = convertToTrafficStatistics(msg); |
|||
|
|||
// 2. 将转换后的数据添加到缓存中
|
|||
DailyTrafficStatisticsCache.addCacheData(dcTrafficSectionData); |
|||
} |
|||
|
|||
/** |
|||
* 将设备实时消息转换为交通断面数据统计定义对象 |
|||
* |
|||
* @param msg JSON格式的设备实时消息 |
|||
* @return 转换后的交通断面数据统计定义对象 |
|||
*/ |
|||
public DcTrafficSectionData convertToTrafficStatistics(JSONObject msg) { |
|||
DcTrafficSectionData dcTrafficSectionData = new DcTrafficSectionData(); |
|||
|
|||
// TODO
|
|||
return dcTrafficSectionData; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 定义每小时第20分钟执行的任务,用于清除过期缓存数据并将缓存中的数据整合后保存至数据库。 |
|||
*/ |
|||
@Scheduled(cron = "0 20 * * * ?") // 每小时的20分整点执行该任务
|
|||
public void performHourlyCleanupAndPersist() { |
|||
// 清除已过期的缓存数据
|
|||
DailyTrafficStatisticsCache.clearExpiredData(); |
|||
MonthlyTrafficStatisticsCache.clearExpiredData(); |
|||
QuarterlyTrafficStatisticsCache.clearExpiredData(); |
|||
YearlyTrafficStatisticsCache.clearExpiredData(); |
|||
// 整合缓存数据并保存至数据库
|
|||
// 将缓存中的数据按日统计后保存至数据库
|
|||
// 添加月交通断面数据到缓存中
|
|||
persistAggregatedData(DailyTrafficStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.DAY, MonthlyTrafficStatisticsCache::addCacheData); |
|||
// 将缓存中的数据按月统计后保存至数据库
|
|||
// 添加季度交通断面数据到缓存中
|
|||
persistAggregatedData(MonthlyTrafficStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.MONTH, QuarterlyTrafficStatisticsCache::addCacheData); |
|||
// 将缓存中的数据按季度统计后保存至数据库
|
|||
// 添加年交通断面数据到缓存中
|
|||
persistAggregatedData(QuarterlyTrafficStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.QUARTER, YearlyTrafficStatisticsCache::addCacheData); |
|||
// 将缓存中的数据按年统计后保存至数据库
|
|||
persistAggregatedData(YearlyTrafficStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.YEAR, (a) -> {}); |
|||
} |
|||
|
|||
/** |
|||
* 将缓存中的数据统计后保存至数据库。 |
|||
*/ |
|||
public void persistAggregatedData( |
|||
Map<String, ? extends AbstractTrafficStatisticsCache> cache, |
|||
TrafficDataPeriodTypeEnum periodType, |
|||
Consumer<DcTrafficSectionData> consumer |
|||
) { |
|||
for (AbstractTrafficStatisticsCache data : cache.values()) { |
|||
// 如果数据已经存储过,则跳过此次处理
|
|||
if (data.isStored()) { |
|||
continue; |
|||
} |
|||
DcTrafficSectionData aggregatedData = RealtimeTrafficStatistics.trafficStatistics(data.getData(), periodType); |
|||
if (dcTrafficSectionDataMapper.insertOrUpdate(aggregatedData)) { |
|||
// 设置数据已存储状态
|
|||
data.setStored(true); |
|||
// 调用回调函数
|
|||
consumer.accept(aggregatedData); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 将计算给定列表中所有交通断面数据的统计结果保存至数据库 |
|||
*/ |
|||
public boolean persistData(DcTrafficSectionData aggregatedData) { |
|||
|
|||
if (aggregatedData == null) { |
|||
return false; |
|||
} |
|||
|
|||
// 创建更新条件封装器
|
|||
LambdaUpdateWrapper<DcTrafficSectionData> updateWrapper = new LambdaUpdateWrapper<>(); |
|||
|
|||
// 设置更新条件:根据设备ID、方向、时段类型、桩号、统计时间查找记录
|
|||
updateWrapper.eq(DcTrafficSectionData::getDeviceId, aggregatedData.getDeviceId()); |
|||
// 方向
|
|||
updateWrapper.eq(DcTrafficSectionData::getDirection, aggregatedData.getDirection()); |
|||
// 时段类型
|
|||
updateWrapper.eq(DcTrafficSectionData::getPeriodType, aggregatedData.getPeriodType()); |
|||
// 桩号
|
|||
updateWrapper.eq(DcTrafficSectionData::getStakeMark, aggregatedData.getStakeMark()); |
|||
// 统计时间
|
|||
updateWrapper.eq(DcTrafficSectionData::getStatisticalDate, aggregatedData.getStatisticalDate()); |
|||
|
|||
|
|||
if (this.update(aggregatedData, updateWrapper)) { |
|||
return true; |
|||
} else { |
|||
// 更新失败则尝试插入
|
|||
aggregatedData.setCreateTime(DateUtils.getNowDate()); |
|||
return this.save(aggregatedData); |
|||
} |
|||
} |
|||
|
|||
|
|||
/* public boolean persistData(DcTrafficSectionData aggregatedData) { |
|||
|
|||
if (aggregatedData == null) { |
|||
return false; |
|||
} |
|||
|
|||
// 创建更新条件封装器
|
|||
LambdaUpdateWrapper<DcTrafficSectionData> updateWrapper = new LambdaUpdateWrapper<>(); |
|||
|
|||
// 设置更新条件:根据设备ID、方向、时段类型、桩号、统计时间查找记录
|
|||
updateWrapper.eq(DcTrafficSectionData::getDeviceId, aggregatedData.getDeviceId()); |
|||
// 方向
|
|||
updateWrapper.eq(DcTrafficSectionData::getDirection, aggregatedData.getDirection()); |
|||
// 时段类型
|
|||
updateWrapper.eq(DcTrafficSectionData::getPeriodType, aggregatedData.getPeriodType()); |
|||
// 桩号
|
|||
updateWrapper.eq(DcTrafficSectionData::getStakeMark, aggregatedData.getStakeMark()); |
|||
// 统计时间
|
|||
updateWrapper.eq(DcTrafficSectionData::getStatisticalDate, aggregatedData.getStatisticalDate()); |
|||
|
|||
|
|||
if (this.update(aggregatedData, updateWrapper)) { |
|||
return true; |
|||
} else { |
|||
// 更新失败则尝试插入
|
|||
aggregatedData.setCreateTime(DateUtils.getNowDate()); |
|||
return this.save(aggregatedData); |
|||
} |
|||
}*/ |
|||
|
|||
|
|||
} |
@ -0,0 +1,47 @@ |
|||
package com.zc.business.statistics.cache; |
|||
|
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 交通断面数据缓存定义 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public abstract class AbstractTrafficStatisticsCache { |
|||
|
|||
// 日志记录器
|
|||
protected final Logger logger = LoggerFactory.getLogger(this.getClass()); |
|||
|
|||
/** |
|||
* 缓存对象的键,由设备ID与统计日期组成 |
|||
*/ |
|||
private String cacheKey; |
|||
|
|||
/** |
|||
* 设备上报日期字符串 |
|||
*/ |
|||
private String statisticalDateStr; |
|||
|
|||
/** |
|||
* 数据最后添加到缓存中的时间 |
|||
*/ |
|||
private Date lastAddedTime; |
|||
|
|||
/** |
|||
* 标记该缓存实例是否已存储过数据 |
|||
*/ |
|||
private boolean stored; |
|||
|
|||
/** |
|||
* 存储具体交通断面数据的列表 |
|||
*/ |
|||
private Collection<DcTrafficSectionData> data; |
|||
} |
@ -0,0 +1,139 @@ |
|||
package com.zc.business.statistics.cache; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.*; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* |
|||
* 以天为单位的交通交通断面数据缓存类,用于存储和管理设备上报的交通断面统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class DailyTrafficStatisticsCache extends AbstractTrafficStatisticsCache { |
|||
|
|||
@Getter |
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
private static final Map<String, DailyTrafficStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = 25 * 60 * 60; // 缓存数据最长保留25小时
|
|||
|
|||
// 最大容量限制(一个设备),防止内存溢出
|
|||
private static final int MAX_CAPACITY = 60/5 * (24 + 1) + 1000; // 缓存的最大条目数
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private DailyTrafficStatisticsCache() { |
|||
super(); |
|||
this.setData(new ArrayList<>()); |
|||
} |
|||
|
|||
/** |
|||
* 添加交通断面数据到缓存中 |
|||
* |
|||
* @param dcTrafficSectionData 待添加的交通断面统计数据 |
|||
*/ |
|||
public static void addCacheData(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 获取或新建对应的缓存实例
|
|||
DailyTrafficStatisticsCache instance = getInstance(dcTrafficSectionData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("交通断面数据缓存出现异常,最大缓存量达到设定上线 {}, 当前设备是 {}", MAX_CAPACITY, dcTrafficSectionData.getDeviceId()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcTrafficSectionData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcTrafficSectionData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
dcTrafficSectionData.setStatisticalDate(dcTrafficSectionData.getStatisticalDate(), TrafficDataPeriodTypeEnum.DAY); |
|||
|
|||
// 将新数据添加到数据列表中
|
|||
instance.getData().add(dcTrafficSectionData); |
|||
} |
|||
|
|||
/** |
|||
* 获取或创建对应设备与日期的DcTrafficSectionDataCache实例 |
|||
* |
|||
* @param dcTrafficSectionData 交通断面数据统计定义 |
|||
* @return 对应的交通断面数据缓存实例 |
|||
*/ |
|||
private static DailyTrafficStatisticsCache getInstance(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcTrafficSectionData), k -> new DailyTrafficStatisticsCache()); |
|||
} |
|||
|
|||
/** |
|||
* 该方法用于生成一个基于DcTrafficSectionData对象属性的唯一键字符串。 |
|||
* 这个键由设备ID与统计日期两部分组成,通常用于索引或标识特定设备在某一日期的交通流量数据。 |
|||
* |
|||
* @param dcTrafficSectionData DcTrafficSectionData类型的对象,包含设备ID和统计日期等信息 |
|||
* @return 格式化后的字符串键,格式为 "deviceId|formattedDate" |
|||
*/ |
|||
public static String generateCacheKey(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 获取设备ID
|
|||
Long deviceId = dcTrafficSectionData.getDeviceId(); |
|||
|
|||
// 获取并格式化统计日期
|
|||
String formattedDate = formatDate(dcTrafficSectionData.getStatisticalDate()); |
|||
|
|||
// 使用"|"字符连接设备ID和日期,形成唯一键
|
|||
return deviceId + "|" + formattedDate; |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(DailyTrafficStatisticsCache::isCacheItemExpire) |
|||
.collect(Collectors.toSet()); |
|||
|
|||
// 安全地从缓存中删除这些过期项
|
|||
keysToRemove.forEach(cache::remove); |
|||
} |
|||
|
|||
/** |
|||
* 检查给定缓存键所对应的缓存项是否已经过期 |
|||
* |
|||
* @param key 缓存key |
|||
* @return 如果已过期则返回true,否则返回false |
|||
*/ |
|||
private static boolean isCacheItemExpire(String key) { |
|||
Date lastAddedTime = cache.get(key).getLastAddedTime(); |
|||
Date currentTime = DateUtil.date(); |
|||
long betweenSecond = DateUtil.between(lastAddedTime, currentTime, DateUnit.SECOND); |
|||
return betweenSecond > MAX_CACHE_TIME; |
|||
} |
|||
|
|||
/** |
|||
* 将 Date 类型的日期格式化为指定格式的字符串。 |
|||
* |
|||
* @param date 需要格式化的 Date 对象。 |
|||
* @return 格式化后的日期字符串。 |
|||
*/ |
|||
private static String formatDate(Date date) { |
|||
// 使用 DateUtil 工具类将 date 格式化为指定格式的字符串
|
|||
return DateUtil.formatDate(date); |
|||
} |
|||
} |
@ -0,0 +1,139 @@ |
|||
package com.zc.business.statistics.cache; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.*; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 以月为单位的交通交通断面数据缓存类,用于存储和管理设备上报的交通断面统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class MonthlyTrafficStatisticsCache extends AbstractTrafficStatisticsCache { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, MonthlyTrafficStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = (60 * 60) * (31 * 24 + 1); |
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 31 + 1000; // 缓存的最大条目数
|
|||
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private MonthlyTrafficStatisticsCache() { |
|||
super(); |
|||
this.setData(new HashSet<>()); |
|||
} |
|||
|
|||
/** |
|||
* 添加交通断面数据到缓存中 |
|||
* |
|||
* @param dcTrafficSectionData 待添加的交通断面统计数据 |
|||
*/ |
|||
public static void addCacheData(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 获取或新建对应的缓存实例
|
|||
MonthlyTrafficStatisticsCache instance = getInstance(dcTrafficSectionData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("交通断面数据缓存出现异常,最大缓存量达到设定上线 {}, 当前设备是 {}", MAX_CAPACITY, dcTrafficSectionData.getDeviceId()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcTrafficSectionData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcTrafficSectionData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
dcTrafficSectionData.setStatisticalDate(dcTrafficSectionData.getStatisticalDate(), TrafficDataPeriodTypeEnum.MONTH); |
|||
|
|||
// 将新数据添加到数据列表中
|
|||
instance.getData().add(dcTrafficSectionData); |
|||
} |
|||
|
|||
/** |
|||
* 获取或创建对应设备与日期的DcTrafficSectionDataCache实例 |
|||
* |
|||
* @param dcTrafficSectionData 交通断面数据统计定义 |
|||
* @return 对应的交通断面数据缓存实例 |
|||
*/ |
|||
private static MonthlyTrafficStatisticsCache getInstance(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcTrafficSectionData), k -> new MonthlyTrafficStatisticsCache()); |
|||
} |
|||
|
|||
/** |
|||
* 该方法用于生成一个基于DcTrafficSectionData对象属性的唯一键字符串。 |
|||
* 这个键由设备ID与统计日期两部分组成,通常用于索引或标识特定设备在某一日期的交通流量数据。 |
|||
* |
|||
* @param dcTrafficSectionData DcTrafficSectionData类型的对象,包含设备ID和统计日期等信息 |
|||
* @return 格式化后的字符串键,格式为 "deviceId|formattedDate" |
|||
*/ |
|||
public static String generateCacheKey(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 获取设备ID
|
|||
Long deviceId = dcTrafficSectionData.getDeviceId(); |
|||
|
|||
// 获取并格式化统计日期
|
|||
String formattedDate = formatDate(dcTrafficSectionData.getStatisticalDate()); |
|||
|
|||
// 使用"|"字符连接设备ID和日期,形成唯一键
|
|||
return deviceId + "|" + formattedDate; |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(MonthlyTrafficStatisticsCache::isCacheItemExpire) |
|||
.collect(Collectors.toSet()); |
|||
|
|||
// 安全地从缓存中删除这些过期项
|
|||
keysToRemove.forEach(cache::remove); |
|||
} |
|||
|
|||
/** |
|||
* 检查给定缓存键所对应的缓存项是否已经过期 |
|||
* |
|||
* @param key 缓存key |
|||
* @return 如果已过期则返回true,否则返回false |
|||
*/ |
|||
private static boolean isCacheItemExpire(String key) { |
|||
Date lastAddedTime = cache.get(key).getLastAddedTime(); |
|||
Date currentTime = DateUtil.date(); |
|||
long betweenSecond = DateUtil.between(lastAddedTime, currentTime, DateUnit.SECOND); |
|||
return betweenSecond > MAX_CACHE_TIME; |
|||
} |
|||
|
|||
/** |
|||
* 将 Date 类型的日期格式化为 "yyyy-MM-01" 格式的字符串。 |
|||
* @param date 需要格式化的日期对象。 |
|||
* @return 格式化后的日期字符串。 |
|||
*/ |
|||
private static String formatDate(Date date) { |
|||
// 使用 DateUtil 工具类将 date 格式化为指定格式的字符串
|
|||
return DateUtil.format(date, "yyyy-MM-01"); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,144 @@ |
|||
package com.zc.business.statistics.cache; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.HashSet; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 以季度为单位的交通交通断面数据缓存类,用于存储和管理设备上报的交通断面统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class QuarterlyTrafficStatisticsCache extends AbstractTrafficStatisticsCache { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, QuarterlyTrafficStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = (60 * 60) * (3 * 31 * 24 + 1); |
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 3 + 1000; // 缓存的最大条目数
|
|||
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private QuarterlyTrafficStatisticsCache() { |
|||
super(); |
|||
this.setData(new HashSet<>()); |
|||
} |
|||
|
|||
/** |
|||
* 添加交通断面数据到缓存中 |
|||
* |
|||
* @param dcTrafficSectionData 待添加的交通断面统计数据 |
|||
*/ |
|||
public static void addCacheData(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 获取或新建对应的缓存实例
|
|||
QuarterlyTrafficStatisticsCache instance = getInstance(dcTrafficSectionData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("交通断面数据缓存出现异常,最大缓存量达到设定上线 {}, 当前设备是 {}", MAX_CAPACITY, dcTrafficSectionData.getDeviceId()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcTrafficSectionData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcTrafficSectionData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
dcTrafficSectionData.setStatisticalDate(dcTrafficSectionData.getStatisticalDate(), TrafficDataPeriodTypeEnum.QUARTER); |
|||
|
|||
// 将新数据添加到数据列表中
|
|||
instance.getData().add(dcTrafficSectionData); |
|||
} |
|||
|
|||
/** |
|||
* 获取或创建对应设备与日期的DcTrafficSectionDataCache实例 |
|||
* |
|||
* @param dcTrafficSectionData 交通断面数据统计定义 |
|||
* @return 对应的交通断面数据缓存实例 |
|||
*/ |
|||
private static QuarterlyTrafficStatisticsCache getInstance(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcTrafficSectionData), k -> new QuarterlyTrafficStatisticsCache()); |
|||
} |
|||
|
|||
/** |
|||
* 该方法用于生成一个基于DcTrafficSectionData对象属性的唯一键字符串。 |
|||
* 这个键由设备ID与统计日期两部分组成,通常用于索引或标识特定设备在某一日期的交通流量数据。 |
|||
* |
|||
* @param dcTrafficSectionData DcTrafficSectionData类型的对象,包含设备ID和统计日期等信息 |
|||
* @return 格式化后的字符串键,格式为 "deviceId|formattedDate" |
|||
*/ |
|||
public static String generateCacheKey(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 获取设备ID
|
|||
Long deviceId = dcTrafficSectionData.getDeviceId(); |
|||
|
|||
// 获取并格式化统计日期
|
|||
String formattedDate = formatDate(dcTrafficSectionData.getStatisticalDate()); |
|||
|
|||
// 使用"|"字符连接设备ID和日期,形成唯一键
|
|||
return deviceId + "|" + formattedDate; |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(QuarterlyTrafficStatisticsCache::isCacheItemExpire) |
|||
.collect(Collectors.toSet()); |
|||
|
|||
// 安全地从缓存中删除这些过期项
|
|||
keysToRemove.forEach(cache::remove); |
|||
} |
|||
|
|||
/** |
|||
* 检查给定缓存键所对应的缓存项是否已经过期 |
|||
* |
|||
* @param key 缓存key |
|||
* @return 如果已过期则返回true,否则返回false |
|||
*/ |
|||
private static boolean isCacheItemExpire(String key) { |
|||
Date lastAddedTime = cache.get(key).getLastAddedTime(); |
|||
Date currentTime = DateUtil.date(); |
|||
long betweenSecond = DateUtil.between(lastAddedTime, currentTime, DateUnit.SECOND); |
|||
return betweenSecond > MAX_CACHE_TIME; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 将 Date 类型的日期格式化为 "yyyy-MM-01" 格式字符串。 |
|||
* |
|||
* @param date 需要格式化的日期对象。 |
|||
* @return 格式化后的日期字符串,格式为 "yyyy-MM-01"。 |
|||
*/ |
|||
private static String formatDate(Date date) { |
|||
// 使用 DateUtil 工具类将 date 格式化为指定格式的字符串
|
|||
return DateUtil.format(date, "yyyy-MM-01"); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,143 @@ |
|||
package com.zc.business.statistics.cache; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.HashSet; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 以年为单位的交通交通断面数据缓存类,用于存储和管理设备上报的交通断面统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class YearlyTrafficStatisticsCache extends AbstractTrafficStatisticsCache { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, YearlyTrafficStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = (60 * 60) * (366 * 24 + 1); |
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 4 + 1000; // 缓存的最大条目数
|
|||
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private YearlyTrafficStatisticsCache() { |
|||
super(); |
|||
this.setData(new HashSet<>()); |
|||
} |
|||
|
|||
/** |
|||
* 添加交通断面数据到缓存中 |
|||
* |
|||
* @param dcTrafficSectionData 待添加的交通断面统计数据 |
|||
*/ |
|||
public static void addCacheData(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 获取或新建对应的缓存实例
|
|||
YearlyTrafficStatisticsCache instance = getInstance(dcTrafficSectionData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("交通断面数据缓存出现异常,最大缓存量达到设定上线 {}, 当前设备是 {}", MAX_CAPACITY, dcTrafficSectionData.getDeviceId()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcTrafficSectionData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcTrafficSectionData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
dcTrafficSectionData.setStatisticalDate(dcTrafficSectionData.getStatisticalDate(), TrafficDataPeriodTypeEnum.YEAR); |
|||
|
|||
// 将新数据添加到数据列表中
|
|||
instance.getData().add(dcTrafficSectionData); |
|||
} |
|||
|
|||
/** |
|||
* 获取或创建对应设备与日期的DcTrafficSectionDataCache实例 |
|||
* |
|||
* @param dcTrafficSectionData 交通断面数据统计定义 |
|||
* @return 对应的交通断面数据缓存实例 |
|||
*/ |
|||
private static YearlyTrafficStatisticsCache getInstance(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcTrafficSectionData), k -> new YearlyTrafficStatisticsCache()); |
|||
} |
|||
|
|||
/** |
|||
* 该方法用于生成一个基于DcTrafficSectionData对象属性的唯一键字符串。 |
|||
* 这个键由设备ID与统计日期两部分组成,通常用于索引或标识特定设备在某一日期的交通流量数据。 |
|||
* |
|||
* @param dcTrafficSectionData DcTrafficSectionData类型的对象,包含设备ID和统计日期等信息 |
|||
* @return 格式化后的字符串键,格式为 "deviceId|formattedDate" |
|||
*/ |
|||
public static String generateCacheKey(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 获取设备ID
|
|||
Long deviceId = dcTrafficSectionData.getDeviceId(); |
|||
|
|||
// 获取并格式化统计日期
|
|||
String formattedDate = formatDate(dcTrafficSectionData.getStatisticalDate()); |
|||
|
|||
// 使用"|"字符连接设备ID和日期,形成唯一键
|
|||
return deviceId + "|" + formattedDate; |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(YearlyTrafficStatisticsCache::isCacheItemExpire) |
|||
.collect(Collectors.toSet()); |
|||
|
|||
// 安全地从缓存中删除这些过期项
|
|||
keysToRemove.forEach(cache::remove); |
|||
} |
|||
|
|||
/** |
|||
* 检查给定缓存键所对应的缓存项是否已经过期 |
|||
* |
|||
* @param key 缓存key |
|||
* @return 如果已过期则返回true,否则返回false |
|||
*/ |
|||
private static boolean isCacheItemExpire(String key) { |
|||
Date lastAddedTime = cache.get(key).getLastAddedTime(); |
|||
Date currentTime = DateUtil.date(); |
|||
long betweenSecond = DateUtil.between(lastAddedTime, currentTime, DateUnit.SECOND); |
|||
return betweenSecond > MAX_CACHE_TIME; |
|||
} |
|||
|
|||
/** |
|||
* 将 Date 类型的日期格式化为 "yyyy-01-01" 格式的字符串。 |
|||
* |
|||
* @param date 需要格式化的日期对象。 |
|||
* @return 格式化后的日期字符串。 |
|||
*/ |
|||
private static String formatDate(Date date) { |
|||
// 使用 DateUtil 工具类将 date 格式化为 "yyyy-01-01" 格式的字符串
|
|||
return DateUtil.format(date, "yyyy-01-01"); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,70 @@ |
|||
package com.zc.business.statistics.handler; |
|||
|
|||
import com.ruoyi.common.utils.DateUtils; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import org.springframework.util.CollectionUtils; |
|||
|
|||
import java.util.Collection; |
|||
|
|||
public class RealtimeTrafficStatistics { |
|||
|
|||
/** |
|||
* 对给定的交通数据集合进行统计分析,返回一个综合交通数据对象。 |
|||
* |
|||
* @param dataCollection 交通数据集合,不可为null或空。包含多个交通路段的详细数据。 |
|||
* @param trafficDataPeriodType 交通数据的时段类型,例如:小时、日、周等。 |
|||
* @return 综合交通数据对象,包含车流量总和、平均车速等统计结果。如果输入数据为空,则返回null。 |
|||
*/ |
|||
public static DcTrafficSectionData trafficStatistics(Collection<DcTrafficSectionData> dataCollection, TrafficDataPeriodTypeEnum trafficDataPeriodType) { |
|||
|
|||
// 判断输入数据是否为空
|
|||
if (CollectionUtils.isEmpty(dataCollection)) { |
|||
return null; |
|||
} |
|||
|
|||
// 创建一个汇总统计用的对象
|
|||
DcTrafficSectionData aggregatedData = new DcTrafficSectionData(); |
|||
|
|||
// 初始化车流量总和和计算平均车速所需的分子部分
|
|||
int trafficVolume = 0; |
|||
double numerator = 0; |
|||
|
|||
// 遍历原始数据列表,累加车流量并计算平均车速
|
|||
for (DcTrafficSectionData data: dataCollection) { |
|||
// 累加车流量
|
|||
trafficVolume += data.getTrafficVolume(); |
|||
// 计算分子部分
|
|||
numerator += data.getAverageSpeed() * data.getTrafficVolume(); |
|||
} |
|||
|
|||
// 使用第一个数据项的信息填充汇总统计对象的基本属性(设备ID、桩号、方向)
|
|||
DcTrafficSectionData firstDcTrafficSectionData = dataCollection.iterator().next(); |
|||
// 设备id
|
|||
aggregatedData.setDeviceId(firstDcTrafficSectionData.getDeviceId()); |
|||
// 桩号
|
|||
aggregatedData.setStakeMark(firstDcTrafficSectionData.getStakeMark()); |
|||
// 道路方向
|
|||
aggregatedData.setDirection(firstDcTrafficSectionData.getDirection()); |
|||
|
|||
// 计算平均车速并设置到汇总统计对象中
|
|||
if (trafficVolume != 0) { |
|||
aggregatedData.setAverageSpeed((int) Math.round(numerator / trafficVolume)); |
|||
} else { |
|||
// 若车流量为0,则默认设置平均车速为0
|
|||
aggregatedData.setAverageSpeed(0); |
|||
} |
|||
// 时段类型
|
|||
aggregatedData.setPeriodType(trafficDataPeriodType); |
|||
// 设置统计时间
|
|||
aggregatedData.setStatisticalDate(firstDcTrafficSectionData.getStatisticalDate(), trafficDataPeriodType); |
|||
// 车流量
|
|||
aggregatedData.setTrafficVolume(trafficVolume); |
|||
// 更新或插入操作
|
|||
aggregatedData.setUpdateTime(DateUtils.getNowDate()); |
|||
// 生成主键
|
|||
aggregatedData.generateUniqueId(); |
|||
|
|||
return aggregatedData; |
|||
} |
|||
} |
@ -0,0 +1,44 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<!DOCTYPE mapper |
|||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
|||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|||
<mapper namespace="com.zc.business.mapper.DcTrafficSectionDataMapper"> |
|||
|
|||
<!-- 插入或更新交通路段数据 --> |
|||
<insert id="insertOrUpdate" parameterType="com.zc.business.domain.DcTrafficSectionData"> |
|||
INSERT INTO |
|||
dc_traffic_section_data |
|||
( |
|||
id, |
|||
traffic_volume, |
|||
average_speed, |
|||
device_id, |
|||
statistical_date, |
|||
direction, |
|||
period_type, |
|||
stake_mark, |
|||
create_time |
|||
) |
|||
VALUES |
|||
( |
|||
#{id}, |
|||
#{trafficVolume}, |
|||
#{averageSpeed}, |
|||
#{deviceId}, |
|||
#{statisticalDate}, |
|||
#{direction}, |
|||
#{periodType}, |
|||
#{stakeMark}, |
|||
NOW()) |
|||
ON DUPLICATE KEY UPDATE |
|||
traffic_volume = VALUES(traffic_volume), |
|||
average_speed = VALUES(average_speed), |
|||
device_id = VALUES(device_id), |
|||
statistical_date = VALUES(statistical_date), |
|||
direction = VALUES(direction), |
|||
period_type = VALUES(period_type), |
|||
stake_mark = VALUES(stake_mark), |
|||
update_time = VALUES(NOW()) |
|||
</insert> |
|||
|
|||
</mapper> |
Loading…
Reference in new issue