58 changed files with 5023 additions and 791 deletions
@ -0,0 +1,67 @@ |
|||
package com.zc.business.domain; |
|||
|
|||
import cn.hutool.core.date.DateUtil; |
|||
import lombok.Data; |
|||
import org.apache.commons.codec.digest.DigestUtils; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Objects; |
|||
|
|||
/** |
|||
* 门架数据统计实体类 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Data |
|||
public class DcGantryStatisticsData extends DcStatisticsData implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 门架标识 |
|||
*/ |
|||
private String gantryCode; |
|||
|
|||
/** |
|||
* 重写equals方法,用于比较两个DcGantryStatisticsData对象是否相等。 |
|||
* |
|||
* @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
|
|||
|
|||
DcGantryStatisticsData that = (DcGantryStatisticsData) o; // 类型转换
|
|||
|
|||
// 使用Objects.equals方法比较对象的各个属性值
|
|||
return Objects.equals(gantryCode, that.gantryCode) && |
|||
Objects.equals(getReportTime(), that.getReportTime()) && |
|||
Objects.equals(getPeriodType(), that.getPeriodType()); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 重写hashCode方法,基于对象的属性生成哈希码。 |
|||
* @return 对象的哈希码值。 |
|||
*/ |
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(gantryCode, getReportTime(), getPeriodType()); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 生成唯一标识符。 |
|||
* 该方法通过将多个属性结合,然后对结合后的字符串进行MD5哈希处理来生成一个唯一标识符。 |
|||
* 结合的属性包括:门架站点标识、统计日期、道路方向、统计粒度和出入类型。 |
|||
*/ |
|||
@Override |
|||
public void generateUniqueId() { |
|||
// 将多个属性按照指定格式组合成一个字符串
|
|||
String combinedAttributes = gantryCode + "_" + DateUtil.format(getStatisticalDate(), "yyyyMMdd_HHmmss") + "_" + getPeriodType(); |
|||
// 对组合后的字符串进行MD5哈希处理,生成唯一标识符,并赋值给当前对象的id属性
|
|||
this.setId(DigestUtils.md5Hex(combinedAttributes)); |
|||
} |
|||
} |
@ -0,0 +1,200 @@ |
|||
package com.zc.business.domain; |
|||
|
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.baomidou.mybatisplus.annotation.TableField; |
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import com.ruoyi.common.core.domain.BaseEntity; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import lombok.Data; |
|||
import org.springframework.format.annotation.DateTimeFormat; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
@Data |
|||
public class DcStatisticsData implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 主键 |
|||
*/ |
|||
private String id; |
|||
|
|||
/** |
|||
* 统计时间 |
|||
*/ |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") |
|||
private Date statisticalDate; |
|||
|
|||
/** |
|||
* 上报时间 |
|||
*/ |
|||
@TableField(exist = false) |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") |
|||
private Date reportTime; |
|||
|
|||
/** |
|||
* 车流量 |
|||
*/ |
|||
private Integer trafficVolume; |
|||
|
|||
/** |
|||
* 统计粒度 |
|||
* 1-年 |
|||
* 2-月 |
|||
* 3-季 |
|||
* 4-日 |
|||
*/ |
|||
private Byte periodType; |
|||
|
|||
/** |
|||
* 创建时间 |
|||
*/ |
|||
private Date createTime; |
|||
|
|||
/** |
|||
* 修改时间 |
|||
*/ |
|||
private Date updateTime; |
|||
|
|||
/** |
|||
* 1型客车车流量 |
|||
*/ |
|||
private Integer type1PassengerFlow; |
|||
|
|||
/** |
|||
* 2型客车车流量 |
|||
*/ |
|||
private Integer type2PassengerFlow; |
|||
|
|||
/** |
|||
* 3型客车车流量 |
|||
*/ |
|||
private Integer type3PassengerFlow; |
|||
|
|||
/** |
|||
* 4型客车车流量 |
|||
*/ |
|||
private Integer type4PassengerFlow; |
|||
|
|||
/** |
|||
* 1型货车车流量 |
|||
*/ |
|||
private Integer type1TruckFlow; |
|||
|
|||
/** |
|||
* 2型货车车流量 |
|||
*/ |
|||
private Integer type2TruckFlow; |
|||
|
|||
/** |
|||
* 3型货车车流量 |
|||
*/ |
|||
private Integer type3TruckFlow; |
|||
|
|||
/** |
|||
* 4型货车车流量 |
|||
*/ |
|||
private Integer type4TruckFlow; |
|||
|
|||
/** |
|||
* 5型货车车流量 |
|||
*/ |
|||
private Integer type5TruckFlow; |
|||
|
|||
/** |
|||
* 6型货车车流量 |
|||
*/ |
|||
private Integer type6TruckFlow; |
|||
|
|||
/** |
|||
* 1型专项作业车车流量 |
|||
*/ |
|||
private Integer type1SpecialVehicleFlow; |
|||
|
|||
/** |
|||
* 2型专项作业车车流量 |
|||
*/ |
|||
private Integer type2SpecialVehicleFlow; |
|||
|
|||
/** |
|||
* 3型专项作业车车流量 |
|||
*/ |
|||
private Integer type3SpecialVehicleFlow; |
|||
|
|||
/** |
|||
* 4型专项作业车车流量 |
|||
*/ |
|||
private Integer type4SpecialVehicleFlow; |
|||
|
|||
/** |
|||
* 5型专项作业车车流量 |
|||
*/ |
|||
private Integer type5SpecialVehicleFlow; |
|||
|
|||
/** |
|||
* 6型专项作业车车流量 |
|||
*/ |
|||
private Integer type6SpecialVehicleFlow; |
|||
|
|||
/** |
|||
* 开始时间 |
|||
*/ |
|||
@TableField(exist = false) |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private Date startTime; |
|||
|
|||
/** |
|||
* 结束时间 |
|||
*/ |
|||
@TableField(exist = false) |
|||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private Date endTime; |
|||
|
|||
public void setPeriodType(Byte periodType) { |
|||
this.periodType = periodType; |
|||
} |
|||
|
|||
/** |
|||
* 设置交通数据的统计周期类型。 |
|||
* @param periodType 统计周期类型的枚举值。 |
|||
*/ |
|||
public void setPeriodType(TrafficDataPeriodTypeEnum periodType) { |
|||
this.periodType = periodType.getCode(); // 将枚举类型转换为代码值存储
|
|||
} |
|||
|
|||
/** |
|||
* 根据给定的统计周期类型和日期,设置统计日期为相应周期的起始日期。 |
|||
* @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; |
|||
} |
|||
} |
|||
|
|||
public void generateUniqueId() { |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,80 @@ |
|||
package com.zc.business.domain; |
|||
|
|||
import cn.hutool.core.date.DateUtil; |
|||
import lombok.Data; |
|||
import org.apache.commons.codec.digest.DigestUtils; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Objects; |
|||
|
|||
/** |
|||
* 收费站数据统计实体类 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Data |
|||
public class DcTollStationStatisticsData extends DcStatisticsData implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
// 入口
|
|||
public static final byte ENTRANCE = 1; |
|||
// 出口
|
|||
public static final byte EXIT = 2; |
|||
|
|||
/** |
|||
* 收费站站点标识 |
|||
*/ |
|||
private String tollStationCode; |
|||
|
|||
/** |
|||
* 出入类型 |
|||
* 1-入口 |
|||
* 2-出口 |
|||
*/ |
|||
private Byte accessType; |
|||
|
|||
|
|||
/** |
|||
* 重写equals方法,用于比较两个DcTollStationStatisticsData对象是否相等。 |
|||
* |
|||
* @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
|
|||
|
|||
DcTollStationStatisticsData that = (DcTollStationStatisticsData) o; // 类型转换
|
|||
|
|||
// 使用Objects.equals方法比较对象的各个属性值
|
|||
return Objects.equals(tollStationCode, that.tollStationCode) && |
|||
Objects.equals(getReportTime(), that.getReportTime()) && |
|||
Objects.equals(getPeriodType(), that.getPeriodType()) && |
|||
Objects.equals(accessType, that.accessType); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 重写hashCode方法,基于对象的属性生成哈希码。 |
|||
* @return 对象的哈希码值。 |
|||
*/ |
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(tollStationCode, getReportTime(), getPeriodType(), accessType); |
|||
} |
|||
|
|||
/** |
|||
* 生成唯一标识符。 |
|||
* 该方法通过将多个属性结合,然后对结合后的字符串进行MD5哈希处理来生成一个唯一标识符。 |
|||
* 结合的属性包括:收费站站点标识、统计日期、道路方向、统计粒度和出入类型。 |
|||
*/ |
|||
@Override |
|||
public void generateUniqueId() { |
|||
// 将多个属性按照指定格式组合成一个字符串
|
|||
String combinedAttributes = tollStationCode + "_" + DateUtil.format(getStatisticalDate(), "yyyyMMdd_HHmmss") + "_" + getPeriodType() + "_" + accessType; |
|||
// 对组合后的字符串进行MD5哈希处理,生成唯一标识符,并赋值给当前对象的id属性
|
|||
this.setId(DigestUtils.md5Hex(combinedAttributes)); |
|||
} |
|||
} |
@ -0,0 +1,129 @@ |
|||
package com.zc.business.domain; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableField; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 收费站入口流水数据 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Data |
|||
public class OdsTollEnpassData implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
|
|||
/** |
|||
* 入口通行时间 |
|||
*/ |
|||
private Date entime; |
|||
|
|||
/** |
|||
* 交易流水号(主键) |
|||
*/ |
|||
private String id; |
|||
|
|||
/** |
|||
* 交易编码 |
|||
*/ |
|||
private String transcode; |
|||
|
|||
/** |
|||
* 车道类型 |
|||
*/ |
|||
private Short lanetype; |
|||
|
|||
/** |
|||
* 入口站号 |
|||
*/ |
|||
private String entollstation; |
|||
|
|||
/** |
|||
* 入口车道号 |
|||
*/ |
|||
private String entolllane; |
|||
|
|||
/** |
|||
* 入口站HEX编码 |
|||
*/ |
|||
private String entollstationhex; |
|||
|
|||
/** |
|||
* 入口车道HEX编码 |
|||
*/ |
|||
private String entolllanehex; |
|||
|
|||
/** |
|||
* 入口站号(国标) |
|||
*/ |
|||
private String entollstationid; |
|||
|
|||
/** |
|||
* 入口车道号(国标) |
|||
*/ |
|||
private String entolllaneid; |
|||
|
|||
/** |
|||
* 通行介质类型:1-OBU,2-CPC卡,3-纸券,4-M1卡,9-无通行介质 |
|||
*/ |
|||
private Short mediatype; |
|||
|
|||
/** |
|||
* 过车数量 |
|||
*/ |
|||
private Integer vcount; |
|||
|
|||
/** |
|||
* 车牌号(经过MD5加密) |
|||
*/ |
|||
@TableField("vlp_MD5") |
|||
private String vlpMD5; |
|||
|
|||
/** |
|||
* 车牌颜色 |
|||
*/ |
|||
private Short vlpc; |
|||
|
|||
/** |
|||
* 车型:1-一型客车...(具体车型定义请参考注释) |
|||
*/ |
|||
private Integer vehicletype; |
|||
|
|||
/** |
|||
* 车种:0-普通,8-军警,10-紧急...(具体车种定义请参考注释) |
|||
*/ |
|||
private Short vehicleclass; |
|||
|
|||
/** |
|||
* 入口重量 |
|||
*/ |
|||
private String enweight; |
|||
|
|||
/** |
|||
* 轴组信息 |
|||
*/ |
|||
private String axisinfo; |
|||
|
|||
/** |
|||
* 限载总重(KG) |
|||
*/ |
|||
private Integer limitweight; |
|||
|
|||
/** |
|||
* 超限率 |
|||
*/ |
|||
private Short overweightrate; |
|||
|
|||
/** |
|||
* 入口轴数 |
|||
*/ |
|||
private Integer enaxlecount; |
|||
|
|||
/** |
|||
* 通行标识ID |
|||
*/ |
|||
private String passid; |
|||
} |
@ -0,0 +1,118 @@ |
|||
package com.zc.business.domain; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableField; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 门架流水数据实体类 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Data |
|||
public class OdsTollEtctuData implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 计费交易时间 |
|||
*/ |
|||
private Date transtime; |
|||
|
|||
/** |
|||
* 门架编号 |
|||
*/ |
|||
private String gantryid; |
|||
|
|||
/** |
|||
* 计费交易编号(主键) |
|||
*/ |
|||
private String tradeid; |
|||
|
|||
/** |
|||
* 门架顺序号 |
|||
*/ |
|||
private Integer gantryordernum; |
|||
|
|||
/** |
|||
* 门架 Hex 值 |
|||
*/ |
|||
private String gantryhex; |
|||
|
|||
/** |
|||
* 对向门架 Hex 值 |
|||
*/ |
|||
private String gantryhexopposite; |
|||
|
|||
/** |
|||
* 通行介质类型:1-OBU,2-CPC卡,3-纸券,4-M1卡,9-无通行介质 |
|||
*/ |
|||
private Integer mediatype; |
|||
|
|||
/** |
|||
* 收费单元编号组 |
|||
*/ |
|||
private String tollintervalid; |
|||
|
|||
/** |
|||
* 车牌号(经过MD5加密) |
|||
*/ |
|||
@TableField("vehicleplate_MD5") |
|||
private String vehicleplateMD5; |
|||
|
|||
/** |
|||
* 车型:1-一型客车...(具体车型定义请参考注释) |
|||
*/ |
|||
private Integer vehicletype; |
|||
|
|||
/** |
|||
* 车种:0-普通,8-军警,10-紧急...(具体车种定义请参考注释) |
|||
*/ |
|||
private Integer vehicleclass; |
|||
|
|||
/** |
|||
* 交易类型标识 |
|||
*/ |
|||
private String transtype; |
|||
|
|||
/** |
|||
* 入口车道编号 |
|||
*/ |
|||
private String entolllaneid; |
|||
|
|||
/** |
|||
* 入口站hex字符串 |
|||
*/ |
|||
private String entollstationhex; |
|||
|
|||
/** |
|||
* 入口时间 |
|||
*/ |
|||
private String entime; |
|||
|
|||
/** |
|||
* 入口车道类型 |
|||
*/ |
|||
private String enlanetype; |
|||
|
|||
/** |
|||
* 通行标识ID |
|||
*/ |
|||
private String passid; |
|||
|
|||
/** |
|||
* 交易结果:0-成功,1-失败 |
|||
*/ |
|||
private Integer traderesult; |
|||
|
|||
/** |
|||
* 门架类型:1-路段,2-省界入口,3-省界出口 |
|||
*/ |
|||
private String gantrytype; |
|||
|
|||
/** |
|||
* 计费车型:与车型字段定义相同 |
|||
*/ |
|||
private Integer feevehicletype; |
|||
} |
@ -0,0 +1,212 @@ |
|||
package com.zc.business.domain; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableField; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 收费站出口流水数据实体类 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Data |
|||
public class OdsTollExpassData implements Serializable { |
|||
/** |
|||
* 出口时间 |
|||
*/ |
|||
private Date extime; |
|||
|
|||
/** |
|||
* 交易流水号(主键) |
|||
*/ |
|||
private String id; |
|||
|
|||
/** |
|||
* 交易支付方式:1-出口ETC通行,2-出口ETC刷卡通行,11-现金,12-其他第三方账户支付,13-银联卡支付,16-支付宝,17-微信 |
|||
*/ |
|||
private Short transpaytype; |
|||
|
|||
/** |
|||
* 交易编码 |
|||
*/ |
|||
private String transcode; |
|||
|
|||
/** |
|||
* 入口重量 |
|||
*/ |
|||
private Integer enweight; |
|||
|
|||
/** |
|||
* 入口轴数 |
|||
*/ |
|||
private Integer enaxlecount; |
|||
|
|||
/** |
|||
* 入口站号 |
|||
*/ |
|||
private String entollstation; |
|||
|
|||
/** |
|||
* 入口站名称 |
|||
*/ |
|||
private String entollstationname; |
|||
|
|||
/** |
|||
* 入口车道号 |
|||
*/ |
|||
private String entolllane; |
|||
|
|||
/** |
|||
* 入口站HEX编码 |
|||
*/ |
|||
private String entollstationhex; |
|||
|
|||
/** |
|||
* 入口车道HEX编码 |
|||
*/ |
|||
private String entolllanehex; |
|||
|
|||
/** |
|||
* 入口站号(国标) |
|||
*/ |
|||
private String entollstationid; |
|||
|
|||
/** |
|||
* 入口车道号(国标) |
|||
*/ |
|||
private String entolllaneid; |
|||
|
|||
/** |
|||
* 入口时间 |
|||
*/ |
|||
private String entime; |
|||
|
|||
/** |
|||
* 车道类型:1-ETC车道,2-MTC车道,3-混合车道 |
|||
*/ |
|||
private Short lanetype; |
|||
|
|||
/** |
|||
* 出口站号 |
|||
*/ |
|||
private String extollstation; |
|||
|
|||
/** |
|||
* 出口收费站名称 |
|||
*/ |
|||
private String extollstationname; |
|||
|
|||
/** |
|||
* 出口车道号 |
|||
*/ |
|||
private String extolllane; |
|||
|
|||
/** |
|||
* 出口站HEX编码 |
|||
*/ |
|||
private String extollstationhex; |
|||
|
|||
/** |
|||
* 出口车道HEX编码 |
|||
*/ |
|||
private String extolllanehex; |
|||
|
|||
/** |
|||
* 出口站号(国标) |
|||
*/ |
|||
private String extollstationid; |
|||
|
|||
/** |
|||
* 出口车道号(国标) |
|||
*/ |
|||
private String extolllaneid; |
|||
|
|||
/** |
|||
* 通行介质类型:1-OBU,2-CPC卡,3-纸券,4-M1,9-无通行介质 |
|||
*/ |
|||
private Short mediatype; |
|||
|
|||
/** |
|||
* 过车数量 |
|||
*/ |
|||
private Integer vcount; |
|||
|
|||
/** |
|||
* 入口车牌号(经过MD5加密) |
|||
*/ |
|||
@TableField("envlp_MD5") |
|||
private String envlpMD5; |
|||
|
|||
/** |
|||
* 入口车牌颜色 |
|||
*/ |
|||
private Short envlpc; |
|||
|
|||
/** |
|||
* 出口车牌号(经过MD5加密) |
|||
*/ |
|||
@TableField("exvlp_MD5") |
|||
private String exvlpMD5; |
|||
|
|||
/** |
|||
* 出口车牌颜色 |
|||
*/ |
|||
private Short exvlpc; |
|||
|
|||
/** |
|||
* 入口车型 |
|||
*/ |
|||
private Integer envehicletype; |
|||
|
|||
/** |
|||
* 出口车型 |
|||
*/ |
|||
private Integer exvehicletype; |
|||
|
|||
/** |
|||
* 入口车种 |
|||
*/ |
|||
private Short envehicleclass; |
|||
|
|||
/** |
|||
* 出口车种 |
|||
*/ |
|||
private Short exvehicleclass; |
|||
|
|||
/** |
|||
* 出口重量 |
|||
*/ |
|||
private Integer exweight; |
|||
|
|||
/** |
|||
* 轴组信息 |
|||
*/ |
|||
private String axisinfo; |
|||
|
|||
/** |
|||
* 限载总重(KG) |
|||
*/ |
|||
private Integer limitweight; |
|||
|
|||
/** |
|||
* 超限率 |
|||
*/ |
|||
private Short overweightrate; |
|||
|
|||
/** |
|||
* 轴数 |
|||
*/ |
|||
private Integer axlecount; |
|||
|
|||
/** |
|||
* 交易类型 |
|||
*/ |
|||
private String transtype; |
|||
|
|||
/** |
|||
* 支付类型:1-现金,2-其他第三方账户支付,3-银联卡支付,4-ETC 用户卡,6-支付宝,7-微信 |
|||
*/ |
|||
private Short paytype; |
|||
|
|||
} |
@ -0,0 +1,44 @@ |
|||
package com.zc.business.domain; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableField; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 门架牌识流水数据实体类 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Data |
|||
public class OdsTollViuData implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 抓拍时间 |
|||
*/ |
|||
private Date pictime; |
|||
|
|||
/** |
|||
* 门架编号 |
|||
*/ |
|||
private String gantryid; |
|||
|
|||
/** |
|||
* 车牌识别流水号(主键) |
|||
*/ |
|||
private String picid; |
|||
|
|||
/** |
|||
* 拍摄位置:1表示车头,0表示车尾 |
|||
*/ |
|||
private Integer shootposition; |
|||
|
|||
/** |
|||
* 车牌号(经过MD5加密) |
|||
*/ |
|||
@TableField("vehicleplate_MD5") |
|||
private String vehicleplateMD5; |
|||
|
|||
} |
@ -0,0 +1,26 @@ |
|||
package com.zc.business.enums; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Getter; |
|||
|
|||
/** |
|||
* 设置类型枚举类 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@AllArgsConstructor |
|||
public enum FacilityTypeEnum { |
|||
TOLL_STATION(1, "收费站"), |
|||
BRIDGE(2, "桥梁"), |
|||
INTERCHANGE(3, "互通立交"), |
|||
JUNCTION(4, "枢纽立交"), |
|||
TUNNEL(5, "隧道"), |
|||
SERVICE_AREA(6, "服务区"), |
|||
PARKING_AREA(7, "停车区"), |
|||
RECOVERY_POST(8, "清障驻点"), |
|||
SLOPE(9, "边坡"), |
|||
GANTRY(10, "门架"); |
|||
|
|||
private final int code; |
|||
private final String description; |
|||
} |
@ -0,0 +1,61 @@ |
|||
package com.zc.business.enums; |
|||
|
|||
import lombok.Getter; |
|||
|
|||
|
|||
/** |
|||
* 车辆类型枚举,用于定义不同类型的车辆及其相关信息。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
public enum VehicleTypeEnum { |
|||
// 客车类型
|
|||
TYPE_1_PASSENGER_CAR(1, "1型客车"), |
|||
TYPE_2_PASSENGER_CAR(2, "2型客车"), |
|||
TYPE_3_PASSENGER_CAR(3, "3型客车"), |
|||
TYPE_4_PASSENGER_CAR(4, "4型客车"), |
|||
// 货车类型
|
|||
TYPE_1_TRUCK(11, "1型货车"), |
|||
TYPE_2_TRUCK(12, "2型货车"), |
|||
TYPE_3_TRUCK(13, "3型货车"), |
|||
TYPE_4_TRUCK(14, "4型货车"), |
|||
TYPE_5_TRUCK(15,"5型货车"), |
|||
TYPE_6_TRUCK(16, "6型货车"), |
|||
// 专项作业车类型
|
|||
TYPE_1_SPECIAL_PURPOSE_VEHICLE(21, "1型专项作业车"), |
|||
TYPE_2_SPECIAL_PURPOSE_VEHICLE(22, "2型专项作业车"), |
|||
TYPE_3_SPECIAL_PURPOSE_VEHICLE(23, "3型专项作业车"), |
|||
TYPE_4_SPECIAL_PURPOSE_VEHICLE(24, "4型专项作业车"), |
|||
TYPE_5_SPECIAL_PURPOSE_VEHICLE(25, "5型专项作业车"), |
|||
TYPE_6_SPECIAL_PURPOSE_VEHICLE(26,"6型专项作业车"); |
|||
|
|||
// 枚举类型的成员变量
|
|||
private final Integer value; // 类型代号
|
|||
private final String description; // 类型描述
|
|||
|
|||
/** |
|||
* 构造函数,用于初始化车辆类型枚举。 |
|||
* @param value 车辆类型的代号。 |
|||
* @param description 车辆类型的描述信息。 |
|||
*/ |
|||
VehicleTypeEnum(Integer value, String description) { |
|||
this.value = value; |
|||
this.description = description; |
|||
} |
|||
|
|||
/** |
|||
* 根据描述查找枚举值。 |
|||
* @param value 车辆类型的代号。 |
|||
* @return 对应的车辆类型枚举。 |
|||
* @throws IllegalArgumentException 如果传入的代号无效,则抛出异常。 |
|||
*/ |
|||
public static VehicleTypeEnum fromDescription(Integer value) { |
|||
for (VehicleTypeEnum type : VehicleTypeEnum.values()) { |
|||
if (type.getValue().equals(value)) { |
|||
return type; |
|||
} |
|||
} |
|||
throw new IllegalArgumentException("无效的车辆类型: " + value); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,33 @@ |
|||
package com.zc.business.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.zc.business.domain.DcGantryStatisticsData; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 这是一个接口的注释,用于描述门架数据统计的Mapper。 |
|||
* 它继承了BaseMapper接口,并且指定DcGantryStatisticsData作为映射实体。 |
|||
* |
|||
* @author xiepufeng 这是作者标注,用于指明代码的编写者。 |
|||
*/ |
|||
@Mapper |
|||
public interface DcGantryStatisticsDataMapper extends BaseMapper<DcGantryStatisticsData> { |
|||
|
|||
/** |
|||
* 插入或更新门架数据统计。 |
|||
* |
|||
* @param gantryStatisticsData 门架数据统计对象,包含需要插入或更新的数据。 |
|||
* @return 返回一个布尔值,表示操作是否成功。true表示插入或更新成功,false表示失败。 |
|||
*/ |
|||
boolean insertOrUpdate(DcGantryStatisticsData gantryStatisticsData); |
|||
|
|||
/** |
|||
* 获取最大的统计日期。 |
|||
* |
|||
* @return 返回最大的统计日期。 |
|||
*/ |
|||
Date getMaxStatisticalDate(); |
|||
} |
|||
|
@ -0,0 +1,33 @@ |
|||
package com.zc.business.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 这是一个接口的注释,用于描述收费站数据统计的Mapper。 |
|||
* 它继承了BaseMapper接口,并且指定DcTollStationStatisticsData作为映射实体。 |
|||
* |
|||
* @author xiepufeng 这是作者标注,用于指明代码的编写者。 |
|||
*/ |
|||
@Mapper |
|||
public interface DcTollStationStatisticsDataMapper extends BaseMapper<DcTollStationStatisticsData> { |
|||
|
|||
/** |
|||
* 插入或更新收费站数据统计。 |
|||
* |
|||
* @param tollStatisticsData 收费站数据统计对象,包含需要插入或更新的数据。 |
|||
* @return 返回一个布尔值,表示操作是否成功。true表示插入或更新成功,false表示失败。 |
|||
*/ |
|||
boolean insertOrUpdate(DcTollStationStatisticsData tollStatisticsData); |
|||
|
|||
/** |
|||
* 获取最大的统计日期。 |
|||
* |
|||
* @return 返回最大的统计日期。 |
|||
*/ |
|||
Date getMaxStatisticalDate(); |
|||
} |
|||
|
@ -0,0 +1,13 @@ |
|||
package com.zc.business.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.zc.business.domain.OdsTollEnpassData; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
/** |
|||
* 收费站入口流水数据Mapper接口 |
|||
* |
|||
* @author xiepufeng |
|||
*/ |
|||
@Mapper |
|||
public interface OdsTollEnpassDataMapper extends BaseMapper<OdsTollEnpassData> { |
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.zc.business.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.zc.business.domain.OdsTollEtctuData; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
/** |
|||
* 门架流水数据Mapper接口 |
|||
* |
|||
* @author xiepufeng |
|||
*/ |
|||
@Mapper |
|||
public interface OdsTollEtctuDataMapper extends BaseMapper<OdsTollEtctuData> { |
|||
} |
@ -0,0 +1,15 @@ |
|||
package com.zc.business.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.zc.business.domain.OdsTollEnpassData; |
|||
import com.zc.business.domain.OdsTollExpassData; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
/** |
|||
* 收费站出口流水数据Mapper接口 |
|||
* |
|||
* @author xiepufeng |
|||
*/ |
|||
@Mapper |
|||
public interface OdsTollExpassDataMapper extends BaseMapper<OdsTollExpassData> { |
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.zc.business.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.zc.business.domain.OdsTollViuData; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
/** |
|||
* 门架牌识流水数据Mapper接口 |
|||
* |
|||
* @author xiepufeng |
|||
*/ |
|||
@Mapper |
|||
public interface OdsTollViuDataMapper extends BaseMapper<OdsTollViuData> { |
|||
} |
@ -0,0 +1,37 @@ |
|||
package com.zc.business.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.zc.business.domain.DcGantryStatisticsData; |
|||
import com.zc.business.domain.DcStatisticsData; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 门架数据统计接口。该接口扩展了IService接口,用于对DcGantryStatisticsData类型的实体进行数据库操作。 |
|||
* 主要用于门架数据的增删改查等统计工作。 |
|||
* |
|||
* @author xiepufeng 提供者 |
|||
*/ |
|||
public interface IDcGantryStatisticsDataService extends IService<DcGantryStatisticsData> { |
|||
|
|||
/** |
|||
* 获取过去一小时的DcGantryStatisticsData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含过去一小时所有符合条件的DcGantryStatisticsData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<DcGantryStatisticsData> - 过去一小时的DcGantryStatisticsData数据列表。 |
|||
*/ |
|||
List<DcGantryStatisticsData> lastHourData(); |
|||
|
|||
/** |
|||
* 进行门架数据统计的函数。 |
|||
* 该方法接收一个DcGantryStatisticsData类型的对象作为输入参数,用来包含门架统计所需的各项数据, |
|||
* 然后基于这些数据进行统计处理,并返回一个包含统计结果的DcGantryStatisticsData对象列表。 |
|||
* |
|||
* @param dcGantryStatisticsData 包含门架统计所需数据的对象。 |
|||
* @return 返回一个DcGantryStatisticsData对象的列表,包含统计后的结果。 |
|||
*/ |
|||
List<DcGantryStatisticsData> gantryData(DcGantryStatisticsData dcGantryStatisticsData); |
|||
} |
@ -0,0 +1,36 @@ |
|||
package com.zc.business.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.zc.business.domain.DcStatisticsData; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 收费站数据统计接口。该接口扩展了IService接口,用于对DcTollStationStatisticsData类型的实体进行数据库操作。 |
|||
* 主要用于收费站数据的增删改查等统计工作。 |
|||
* |
|||
* @author xiepufeng 提供者 |
|||
*/ |
|||
public interface IDcTollStationStatisticsDataService extends IService<DcTollStationStatisticsData> { |
|||
|
|||
/** |
|||
* 获取过去一小时的DcTollStationStatisticsData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含过去一小时所有符合条件的DcTollStationStatisticsData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<DcTollStationStatisticsData> - 过去一小时的DcTollStationStatisticsData数据列表。 |
|||
*/ |
|||
List<DcTollStationStatisticsData> lastHourData(); |
|||
|
|||
/** |
|||
* 收费站数据统计函数 |
|||
* |
|||
* 通过对传入的统计数据进行处理,计算并返回收费站数据的统计结果列表。 |
|||
* |
|||
* @param request 包含统计所需参数。 |
|||
* @return 返回一个包收费站站数据统计结果的列表。 |
|||
*/ |
|||
List<DcTollStationStatisticsData> tollStationData(DcTollStationStatisticsData request); |
|||
} |
@ -0,0 +1,66 @@ |
|||
package com.zc.business.service; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.zc.business.domain.DcCongestedSectionData; |
|||
import com.zc.business.domain.DcTrafficMetricsData; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import com.zc.business.request.DcTrafficMetricsDataRequest; |
|||
import com.zc.business.request.DcTrafficSectionDataRequest; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 交通统计服务接口,提供处理交通数据的相关方法 |
|||
* @author xiepufeng |
|||
*/ |
|||
public interface IDcTrafficSectionStatisticsService extends IService<DcTrafficSectionData> { |
|||
|
|||
/** |
|||
* 处理实时接收到的一类交流站设备消息,并将其转换为交通断面统计数据对象并缓存。 |
|||
* |
|||
* @param msg 设备发送的JSON格式实时消息 |
|||
*/ |
|||
void processRealtimeOneStopMessage(JSONObject msg); |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取当前的交通截面数据。 |
|||
* |
|||
* @param request 包含获取交通截面所需的所有请求参数的对象。 |
|||
* @return DcTrafficSectionData 返回一个包含当前交通截面数据列表。 |
|||
*/ |
|||
List<DcTrafficSectionData> currentSections(DcTrafficSectionDataRequest request); |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取历史的交通截面数据。 |
|||
* |
|||
* @param request 包含获取交通截面所需的所有请求参数的对象。 |
|||
* @return DcTrafficSectionData 返回一个包含历史交通截面数据列表。 |
|||
*/ |
|||
List<DcTrafficSectionData> historySections(DcTrafficSectionDataRequest request); |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取当前的交通指标数据。 |
|||
* |
|||
* @param request 包含获取交通指标所需的所有请求参数的对象。 |
|||
* @return DcTrafficMetricsData 返回一个包含当前交通指标数据列表。 |
|||
*/ |
|||
List<DcTrafficMetricsData> currentTrafficMetrics(DcTrafficMetricsDataRequest request); |
|||
|
|||
|
|||
/** |
|||
* 获取历史交通指标数据列表。 |
|||
* |
|||
* @param request 包含获取交通指标所需的所有请求参数的对象。 |
|||
* @return 返回符合查询条件的历史交通指标数据列表。 |
|||
*/ |
|||
List<DcTrafficMetricsData> historyTrafficMetrics(DcTrafficMetricsDataRequest request); |
|||
|
|||
/** |
|||
* 获取当前拥堵路段列表。 |
|||
* |
|||
* @param direction 交通方向,指定查询哪个方向的拥堵路段。具体方向的定义根据实际业务而定。 |
|||
* @return 返回当前拥堵路段列表。 |
|||
*/ |
|||
List<DcCongestedSectionData> currentCongestedSection(Byte direction); |
|||
} |
@ -1,66 +1,16 @@ |
|||
package com.zc.business.service; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.zc.business.domain.DcCongestedSectionData; |
|||
import com.zc.business.domain.DcTrafficMetricsData; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import com.zc.business.request.DcTrafficMetricsDataRequest; |
|||
import com.zc.business.request.DcTrafficSectionDataRequest; |
|||
import com.zc.business.domain.DcStatisticsData; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 交通统计服务接口,提供处理交通数据的相关方法 |
|||
* @author xiepufeng |
|||
*/ |
|||
public interface IDcTrafficStatisticsService extends IService<DcTrafficSectionData> { |
|||
public interface IDcTrafficStatisticsService { |
|||
|
|||
/** |
|||
* 处理实时接收到的一类交流站设备消息,并将其转换为交通断面统计数据对象并缓存。 |
|||
* 根据传入的统计请求数据,查询历史累计车流量数据。 |
|||
* |
|||
* @param msg 设备发送的JSON格式实时消息 |
|||
* @param request 包含统计查询条件的DcStatisticsData对象,用于指定查询的历史流量数据的细节,如时间范围等。 |
|||
* @return 返回一个DcStatisticsData列表。 |
|||
*/ |
|||
void processRealtimeOneStopMessage(JSONObject msg); |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取当前的交通截面数据。 |
|||
* |
|||
* @param request 包含获取交通截面所需的所有请求参数的对象。 |
|||
* @return DcTrafficSectionData 返回一个包含当前交通截面数据列表。 |
|||
*/ |
|||
List<DcTrafficSectionData> currentSections(DcTrafficSectionDataRequest request); |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取历史的交通截面数据。 |
|||
* |
|||
* @param request 包含获取交通截面所需的所有请求参数的对象。 |
|||
* @return DcTrafficSectionData 返回一个包含历史交通截面数据列表。 |
|||
*/ |
|||
List<DcTrafficSectionData> historySections(DcTrafficSectionDataRequest request); |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取当前的交通指标数据。 |
|||
* |
|||
* @param request 包含获取交通指标所需的所有请求参数的对象。 |
|||
* @return DcTrafficMetricsData 返回一个包含当前交通指标数据列表。 |
|||
*/ |
|||
List<DcTrafficMetricsData> currentTrafficMetrics(DcTrafficMetricsDataRequest request); |
|||
|
|||
|
|||
/** |
|||
* 获取历史交通指标数据列表。 |
|||
* |
|||
* @param request 包含获取交通指标所需的所有请求参数的对象。 |
|||
* @return 返回符合查询条件的历史交通指标数据列表。 |
|||
*/ |
|||
List<DcTrafficMetricsData> historyTrafficMetrics(DcTrafficMetricsDataRequest request); |
|||
|
|||
/** |
|||
* 获取当前拥堵路段列表。 |
|||
* |
|||
* @param direction 交通方向,指定查询哪个方向的拥堵路段。具体方向的定义根据实际业务而定。 |
|||
* @return 返回当前拥堵路段列表。 |
|||
*/ |
|||
List<DcCongestedSectionData> currentCongestedSection(Byte direction); |
|||
List<DcStatisticsData> historyFlow(DcStatisticsData request); |
|||
} |
|||
|
@ -0,0 +1,48 @@ |
|||
package com.zc.business.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.domain.OdsTollEnpassData; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 入口流水数据服务接口 |
|||
* 提供对入口流水数据的增删改查等操作 |
|||
* |
|||
* @author xiepufeng |
|||
* @extends IService<OdsTollEnpassData> 继承自IService接口,指定操作的数据类型为OdsTollEnpassData |
|||
*/ |
|||
public interface IOdsTollEnpassDataService extends IService<OdsTollEnpassData> { |
|||
|
|||
|
|||
/** |
|||
* 获取过去一小时的OdsTollEnpassData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含过去一小时所有符合条件的OdsTollEnpassData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollEnpassData> - 过去一小时的OdsTollEnpassData数据列表。 |
|||
*/ |
|||
List<OdsTollEnpassData> lastHourData(); |
|||
|
|||
/** |
|||
* 获取当月的OdsTollEnpassData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含当月所有符合条件的OdsTollEnpassData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollEnpassData> - 当月的OdsTollEnpassData数据列表。 |
|||
*/ |
|||
List<OdsTollEnpassData> currentMonthData(); |
|||
|
|||
/** |
|||
* 计算收费站在指定时间段内的统计数据。 |
|||
* |
|||
* @param list 包含收费通行数据的列表,不应为null或空。 |
|||
* @return 返回一个包含各收费站统计数据的列表。如果输入列表为空,则返回空列表。 |
|||
*/ |
|||
List<DcTollStationStatisticsData> calculateTollStationStatistics(List<OdsTollEnpassData> list); |
|||
|
|||
} |
|||
|
@ -0,0 +1,40 @@ |
|||
package com.zc.business.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.zc.business.domain.DcGantryStatisticsData; |
|||
import com.zc.business.domain.OdsTollEtctuData; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 门架流水数据 |
|||
* @author xiepufeng |
|||
*/ |
|||
public interface IOdsTollEtctuDataService extends IService<OdsTollEtctuData> { |
|||
|
|||
/** |
|||
* 获取最后一小时的门架流水数据列表。 |
|||
* |
|||
* @return List<OdsTollEtctuData> - 返回最后一小时的门架流水数据列表。如果没有数据,则返回空列表。 |
|||
*/ |
|||
List<OdsTollEtctuData> lastHourData(); |
|||
|
|||
/** |
|||
* 获取当月的门架流水数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含当月所有符合条件的门架流水数据对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollEtctuData> - 当月的门架流水数据列表。 |
|||
*/ |
|||
List<OdsTollEtctuData> currentMonthData(); |
|||
|
|||
|
|||
/** |
|||
* 计算门架在指定时间段内的统计数据。 |
|||
* |
|||
* @param odsTollEtctuDataList 包含门架数据的列表,不应为null或空。 |
|||
* @return 返回一个包含各门架统计数据的列表。如果输入列表为空,则返回空列表。 |
|||
*/ |
|||
List<DcGantryStatisticsData> calculateGantryStatistics(List<OdsTollEtctuData> odsTollEtctuDataList); |
|||
} |
@ -0,0 +1,45 @@ |
|||
package com.zc.business.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.domain.OdsTollExpassData; |
|||
import com.zc.business.domain.OdsTollExpassData; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 流水数据操作接口,用于对出口流水数据进行操作。 |
|||
* 该接口继承自IService接口,针对OdsTollExpassData类型的数据提供服务。 |
|||
* |
|||
* @author xiepufeng |
|||
*/ |
|||
public interface IOdsTollExpassDataService extends IService<OdsTollExpassData> { |
|||
/** |
|||
* 获取过去一小时的OdsTollExpassData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含过去一小时所有符合条件的OdsTollExpassData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollExpassData> - 过去一小时的OdsTollExpassData数据列表。 |
|||
*/ |
|||
List<OdsTollExpassData> lastHourData(); |
|||
|
|||
/** |
|||
* 获取当月的OdsTollExpassData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含当月所有符合条件的OdsTollExpassData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollExpassData> - 当月的OdsTollExpassData数据列表。 |
|||
*/ |
|||
List<OdsTollExpassData> currentMonthData(); |
|||
|
|||
/** |
|||
* 计算收费站在指定时间段内的统计数据。 |
|||
* |
|||
* @param list 包含收费通行数据的列表,不应为null或空。 |
|||
* @return 返回一个包含各收费站统计数据的列表。如果输入列表为空,则返回空列表。 |
|||
*/ |
|||
List<DcTollStationStatisticsData> calculateTollStationStatistics(List<OdsTollExpassData> list); |
|||
} |
|||
|
@ -0,0 +1,11 @@ |
|||
package com.zc.business.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.zc.business.domain.OdsTollViuData; |
|||
|
|||
/** |
|||
* 门架牌识流水数据 |
|||
* @author xiepufeng |
|||
*/ |
|||
public interface IOdsTollViuDataService extends IService<OdsTollViuData> { |
|||
} |
@ -0,0 +1,170 @@ |
|||
package com.zc.business.service.impl; |
|||
|
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.ruoyi.common.exception.ServiceException; |
|||
import com.zc.business.domain.DcGantryStatisticsData; |
|||
import com.zc.business.domain.OdsTollEtctuData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.mapper.DcGantryStatisticsDataMapper; |
|||
import com.zc.business.service.*; |
|||
import com.zc.business.statistics.cache.gantry.DailyTrafficGantryStatisticsCache; |
|||
import com.zc.business.statistics.cache.gantry.MonthlyTrafficGantryStatisticsCache; |
|||
import com.zc.business.statistics.cache.gantry.QuarterlyTrafficGantryStatisticsCache; |
|||
import com.zc.business.statistics.cache.gantry.YearlyTrafficGantryStatisticsCache; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import javax.annotation.Resource; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 门架数据统计服务实现类 |
|||
* 该类扩展了ServiceImpl,用于处理DcGantryStatisticsData表的数据库操作。 |
|||
* 实现了IDcGantryStatisticsDataService接口,提门架数据的统计方法。 |
|||
*/ |
|||
@Service |
|||
public class DcGantryStatisticsDataImpl extends ServiceImpl<DcGantryStatisticsDataMapper, DcGantryStatisticsData> |
|||
implements IDcGantryStatisticsDataService { |
|||
|
|||
// 日志记录器
|
|||
protected final Logger logger = LoggerFactory.getLogger(this.getClass()); |
|||
|
|||
// 门架流水数据服务
|
|||
@Resource |
|||
private IOdsTollEtctuDataService odsTollEtctuDataService; |
|||
|
|||
|
|||
/** |
|||
* 初始化方法,用于在对象创建后恢复各种周期的交通门架缓存。 |
|||
* 该方法标注了@PostConstruct注解,确保在依赖注入完成后调用。 |
|||
*/ |
|||
@PostConstruct |
|||
public void init() { |
|||
recoveryDailyCache(); // 从数据库中恢复天的缓存数据(当月天的缓存数据)
|
|||
recoveryMonthlyCache(); // 恢复每月交通门架缓存
|
|||
recoveryQuarterlyCache(); // 恢复每季度交通门架缓存
|
|||
recoveryYearlyCache(); // 恢复每年交通门架缓存
|
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取最后一小时的门架统计数据。 |
|||
* 该方法首先从ODS(数据操作服务)获取过去一小时的门架数据, |
|||
* 然后基于这些数据计算并生成门架的统计信息列表。 |
|||
* |
|||
* @return List<DcGantryStatisticsData> 包含门架统计信息的列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcGantryStatisticsData> lastHourData() { |
|||
|
|||
// 获取门架入口过去一小时的通过数据
|
|||
List<OdsTollEtctuData> odsTollEnpassDataList = odsTollEtctuDataService.lastHourData(); |
|||
|
|||
return odsTollEtctuDataService.calculateGantryStatistics(odsTollEnpassDataList); |
|||
} |
|||
|
|||
/** |
|||
* 进行门架数据统计的函数。 |
|||
* 该方法接收一个DcGantryStatisticsData类型的对象作为输入参数,用来包含门架统计所需的各项数据, |
|||
* 然后基于这些数据进行统计处理,并返回一个包含统计结果的DcGantryStatisticsData对象列表。 |
|||
* |
|||
* @param request 包含门架统计所需数据的对象。 |
|||
* @return 返回一个DcGantryStatisticsData对象的列表,包含统计后的结果。 |
|||
*/ |
|||
@Override |
|||
public List<DcGantryStatisticsData> gantryData(DcGantryStatisticsData request) { |
|||
|
|||
if (request.getStartTime() == null || request.getEndTime() == null) { |
|||
throw new ServiceException("开始时间或结束时间不能为空"); |
|||
} |
|||
|
|||
if (request.getPeriodType() == null) { |
|||
throw new ServiceException("时段类型不能为空"); |
|||
} |
|||
|
|||
if (request.getGantryCode() == null) { |
|||
throw new ServiceException("门架标识不能为空"); |
|||
} |
|||
|
|||
LambdaQueryWrapper<DcGantryStatisticsData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
|
|||
// 如果请求中包含唯一标识符,则根据唯一标识符进行过滤
|
|||
if (request.getId() != null) { |
|||
queryWrapper.eq(DcGantryStatisticsData::getId, request.getId()); |
|||
} |
|||
|
|||
// 如果请求中包含统计日期,则根据统计日期进行过滤
|
|||
if (request.getStatisticalDate() != null) { |
|||
queryWrapper.eq(DcGantryStatisticsData::getStatisticalDate, request.getStatisticalDate()); |
|||
} |
|||
|
|||
queryWrapper.eq(DcGantryStatisticsData::getPeriodType, request.getPeriodType()); |
|||
queryWrapper.eq(DcGantryStatisticsData::getGantryCode, request.getGantryCode()); |
|||
queryWrapper.between(DcGantryStatisticsData::getCreateTime, request.getStartTime(), request.getEndTime()); |
|||
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
/** |
|||
* 恢复日缓存数据的方法 |
|||
* 该方法首先会获取当前月份的门架入口数据, |
|||
* 然后分别计算每个门架的统计信息,并将这些统计信息添加到每日交通门架统计缓存中。 |
|||
*/ |
|||
private void recoveryDailyCache() { |
|||
|
|||
// 获取当月门架数据
|
|||
List<OdsTollEtctuData> odsTollEnpassDataList = odsTollEtctuDataService.currentMonthData(); |
|||
|
|||
// 计算每个门架数据的统计信息,并添加到每日门架统计缓存中
|
|||
odsTollEtctuDataService.calculateGantryStatistics(odsTollEnpassDataList).forEach(DailyTrafficGantryStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每月交通门架缓存的方法。 |
|||
* 通过查询当前月份至今的每日交通数据,并将其添加到每月门架统计缓存中。 |
|||
*/ |
|||
private void recoveryMonthlyCache() { |
|||
// 构建查询条件,查询当前月份至今的每日交通数据
|
|||
LambdaQueryWrapper<DcGantryStatisticsData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcGantryStatisticsData::getPeriodType, TrafficDataPeriodTypeEnum.DAY); |
|||
queryWrapper.between(DcGantryStatisticsData::getStatisticalDate, DateUtil.beginOfMonth(new Date()), new Date()); |
|||
List<DcGantryStatisticsData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每日数据添加到每月门架统计缓存中
|
|||
dcTrafficSectionDataList.forEach(MonthlyTrafficGantryStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每季度交通门架缓存的方法。 |
|||
* 通过查询当前季度至今的每月交通数据,并将其添加到每季度门架统计缓存中。 |
|||
*/ |
|||
private void recoveryQuarterlyCache() { |
|||
// 构建查询条件,查询当前季度至今的每月交通数据
|
|||
LambdaQueryWrapper<DcGantryStatisticsData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcGantryStatisticsData::getPeriodType, TrafficDataPeriodTypeEnum.MONTH); |
|||
queryWrapper.between(DcGantryStatisticsData::getStatisticalDate, DateUtil.beginOfQuarter(new Date()), new Date()); |
|||
List<DcGantryStatisticsData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每月数据添加到每季度门架统计缓存
|
|||
dcTrafficSectionDataList.forEach(QuarterlyTrafficGantryStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每年交通门架缓存的方法。 |
|||
* 通过查询当前年份至今的每季度交通数据,并将其添加到每年门架统计缓存中。 |
|||
*/ |
|||
private void recoveryYearlyCache() { |
|||
// 构建查询条件,查询当前年份至今的每季度交通数据
|
|||
LambdaQueryWrapper<DcGantryStatisticsData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcGantryStatisticsData::getPeriodType, TrafficDataPeriodTypeEnum.QUARTER); |
|||
queryWrapper.between(DcGantryStatisticsData::getStatisticalDate, DateUtil.beginOfYear(new Date()), new Date()); |
|||
List<DcGantryStatisticsData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每季度数据添加到每年门架统计缓存
|
|||
dcTrafficSectionDataList.forEach(YearlyTrafficGantryStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,200 @@ |
|||
package com.zc.business.service.impl; |
|||
|
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.ruoyi.common.exception.ServiceException; |
|||
import com.zc.business.domain.*; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.mapper.DcTollStationStatisticsDataMapper; |
|||
import com.zc.business.service.IDcTollStationStatisticsDataService; |
|||
import com.zc.business.service.IOdsTollEnpassDataService; |
|||
import com.zc.business.service.IOdsTollExpassDataService; |
|||
import com.zc.business.statistics.cache.tollstation.DailyTrafficTollStationStatisticsCache; |
|||
import com.zc.business.statistics.cache.tollstation.MonthlyTrafficTollStationStatisticsCache; |
|||
import com.zc.business.statistics.cache.tollstation.QuarterlyTrafficTollStationStatisticsCache; |
|||
import com.zc.business.statistics.cache.tollstation.YearlyTrafficTollStationStatisticsCache; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import javax.annotation.Resource; |
|||
import java.util.ArrayList; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 收费站数据统计服务实现类 |
|||
* 该类扩展了ServiceImpl,用于处理DcTollStationStatisticsData表的数据库操作。 |
|||
* 实现了IDcTollStationStatisticsDataService接口,提供收费站数据的统计方法。 |
|||
*/ |
|||
@Service |
|||
public class DcTollStationStatisticsDataImpl extends ServiceImpl<DcTollStationStatisticsDataMapper, DcTollStationStatisticsData> |
|||
implements IDcTollStationStatisticsDataService { |
|||
|
|||
// 日志记录器
|
|||
protected final Logger logger = LoggerFactory.getLogger(this.getClass()); |
|||
|
|||
// 收费站入口流水数据
|
|||
@Resource |
|||
private IOdsTollEnpassDataService odsTollEnpassDataService; |
|||
|
|||
// 出口流水数据
|
|||
@Resource |
|||
private IOdsTollExpassDataService odsTollExpassDataService; |
|||
|
|||
/** |
|||
* 初始化方法,用于在对象创建后恢复各种周期的交通收费站站点缓存。 |
|||
* 该方法标注了@PostConstruct注解,确保在依赖注入完成后调用。 |
|||
*/ |
|||
@PostConstruct |
|||
public void init() { |
|||
recoveryDailyCache(); // 从数据库中恢复天的缓存数据(当月天的缓存数据)
|
|||
recoveryMonthlyCache(); // 恢复每月交通收费站站点缓存
|
|||
recoveryQuarterlyCache(); // 恢复每季度交通收费站站点缓存
|
|||
recoveryYearlyCache(); // 恢复每年交通收费站站点缓存
|
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取最后一小时的收费站点统计数据。 |
|||
* 该方法首先从ODS(数据操作服务)获取过去一小时的通过(Enpass)和出口(Expass)数据, |
|||
* 然后基于这些数据计算并生成收费站点的统计信息列表。 |
|||
* |
|||
* @return List<DcTollStationStatisticsData> 包含收费站点统计信息的列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcTollStationStatisticsData> lastHourData() { |
|||
|
|||
// 获取站点入口过去一小时的通过数据
|
|||
List<OdsTollEnpassData> odsTollEnpassDataList = odsTollEnpassDataService.lastHourData(); |
|||
// 获取站点出口过去一小时的通过数据
|
|||
List<OdsTollExpassData> odsTollExpassDataList = odsTollExpassDataService.lastHourData(); |
|||
|
|||
// 初始化用于存放最终统计结果的列表
|
|||
List<DcTollStationStatisticsData> dcTollStationStatisticsDataList = new ArrayList<>(); |
|||
|
|||
// 根据入口和出口数据计算并添加收费站点的统计信息到结果列表中
|
|||
dcTollStationStatisticsDataList.addAll(odsTollEnpassDataService.calculateTollStationStatistics(odsTollEnpassDataList)); |
|||
dcTollStationStatisticsDataList.addAll(odsTollExpassDataService.calculateTollStationStatistics(odsTollExpassDataList)); |
|||
|
|||
return dcTollStationStatisticsDataList; |
|||
} |
|||
|
|||
/** |
|||
* 收费站数据统计函数 |
|||
* <p> |
|||
* 通过对传入的统计数据进行处理,计算并返回收费站数据的统计结果列表。 |
|||
* |
|||
* @param request 包含统计所需参数。 |
|||
* @return 返回一个包收费站站数据统计结果的列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcTollStationStatisticsData> tollStationData(DcTollStationStatisticsData request) { |
|||
|
|||
if (request.getStartTime() == null || request.getEndTime() == null) { |
|||
throw new ServiceException("开始时间或结束时间不能为空"); |
|||
} |
|||
|
|||
if (request.getPeriodType() == null) { |
|||
throw new ServiceException("时段类型不能为空"); |
|||
} |
|||
|
|||
if (request.getTollStationCode() == null) { |
|||
throw new ServiceException("收费站站点编号不能为空"); |
|||
} |
|||
|
|||
|
|||
LambdaQueryWrapper<DcTollStationStatisticsData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
|
|||
|
|||
|
|||
// 如果请求中包含出入类型,则根据出入类型进行过滤
|
|||
if (request.getAccessType() != null) { |
|||
queryWrapper.eq(DcTollStationStatisticsData::getAccessType, request.getAccessType()); |
|||
} |
|||
|
|||
// 如果请求中包含唯一标识符,则根据唯一标识符进行过滤
|
|||
if (request.getId() != null) { |
|||
queryWrapper.eq(DcTollStationStatisticsData::getId, request.getId()); |
|||
} |
|||
|
|||
// 如果请求中包含统计日期,则根据统计日期进行过滤
|
|||
if (request.getStatisticalDate() != null) { |
|||
queryWrapper.eq(DcTollStationStatisticsData::getStatisticalDate, request.getStatisticalDate()); |
|||
} |
|||
|
|||
queryWrapper.eq(DcTollStationStatisticsData::getPeriodType, request.getPeriodType()); |
|||
queryWrapper.between(DcTollStationStatisticsData::getCreateTime, request.getStartTime(), request.getEndTime()); |
|||
queryWrapper.eq(DcTollStationStatisticsData::getTollStationCode, request.getTollStationCode()); |
|||
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 恢复日缓存数据的方法(获取当月收费站站点入口和出口数据)。 |
|||
* 该方法首先会获取当前月份的收费站站点入口和出口数据, |
|||
* 然后分别计算每个收费站的统计信息,并将这些统计信息添加到每日交通收费站统计缓存中。 |
|||
*/ |
|||
private void recoveryDailyCache() { |
|||
|
|||
// 获取当月收费站站点入口数据
|
|||
List<OdsTollEnpassData> odsTollEnpassDataList = odsTollEnpassDataService.currentMonthData(); |
|||
|
|||
// 计算每个收费站入口数据的统计信息,并添加到每日交通收费站统计缓存中
|
|||
odsTollEnpassDataService.calculateTollStationStatistics(odsTollEnpassDataList).forEach(DailyTrafficTollStationStatisticsCache::addCacheData); |
|||
|
|||
// 获取当月收费站站点出口数据
|
|||
List<OdsTollExpassData> odsTollExpassDataList = odsTollExpassDataService.currentMonthData(); |
|||
|
|||
// 计算每个收费站出口数据的统计信息,并添加到每日交通收费站统计缓存中
|
|||
odsTollExpassDataService.calculateTollStationStatistics(odsTollExpassDataList).forEach(DailyTrafficTollStationStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每月交通收费站站点缓存的方法。 |
|||
* 通过查询当前月份至今的每日交通数据,并将其添加到每月交通收费站统计缓存中。 |
|||
*/ |
|||
private void recoveryMonthlyCache() { |
|||
// 构建查询条件,查询当前月份至今的每日交通数据
|
|||
LambdaQueryWrapper<DcTollStationStatisticsData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcTollStationStatisticsData::getPeriodType, TrafficDataPeriodTypeEnum.DAY); |
|||
queryWrapper.between(DcTollStationStatisticsData::getStatisticalDate, DateUtil.beginOfMonth(new Date()), new Date()); |
|||
List<DcTollStationStatisticsData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每日数据添加到每月交通收费站统计缓存中
|
|||
dcTrafficSectionDataList.forEach(MonthlyTrafficTollStationStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每季度交通收费站站点缓存的方法。 |
|||
* 通过查询当前季度至今的每月交通数据,并将其添加到每季度交通收费站统计缓存中。 |
|||
*/ |
|||
private void recoveryQuarterlyCache() { |
|||
// 构建查询条件,查询当前季度至今的每月交通数据
|
|||
LambdaQueryWrapper<DcTollStationStatisticsData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcTollStationStatisticsData::getPeriodType, TrafficDataPeriodTypeEnum.MONTH); |
|||
queryWrapper.between(DcTollStationStatisticsData::getStatisticalDate, DateUtil.beginOfQuarter(new Date()), new Date()); |
|||
List<DcTollStationStatisticsData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每月数据添加到每季度交通收费站统计缓存
|
|||
dcTrafficSectionDataList.forEach(QuarterlyTrafficTollStationStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每年交通收费站站点缓存的方法。 |
|||
* 通过查询当前年份至今的每季度交通数据,并将其添加到每年交通收费站统计缓存中。 |
|||
*/ |
|||
private void recoveryYearlyCache() { |
|||
// 构建查询条件,查询当前年份至今的每季度交通数据
|
|||
LambdaQueryWrapper<DcTollStationStatisticsData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcTollStationStatisticsData::getPeriodType, TrafficDataPeriodTypeEnum.QUARTER); |
|||
queryWrapper.between(DcTollStationStatisticsData::getStatisticalDate, DateUtil.beginOfYear(new Date()), new Date()); |
|||
List<DcTollStationStatisticsData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每季度数据添加到每年交通收费站统计缓存
|
|||
dcTrafficSectionDataList.forEach(YearlyTrafficTollStationStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,506 @@ |
|||
package com.zc.business.service.impl; |
|||
|
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.alibaba.fastjson.JSONArray; |
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.ruoyi.common.core.redis.RedisCache; |
|||
import com.ruoyi.common.exception.ServiceException; |
|||
import com.zc.business.constant.DeviceTypeConstants; |
|||
import com.zc.business.constant.RedisKeyConstants; |
|||
import com.zc.business.controller.DcDeviceController; |
|||
import com.zc.business.domain.*; |
|||
import com.zc.business.enums.*; |
|||
import com.zc.business.request.DcTrafficMetricsDataRequest; |
|||
import com.zc.business.request.DcTrafficSectionDataRequest; |
|||
import com.zc.business.mapper.DcTrafficSectionDataMapper; |
|||
import com.zc.business.service.IDcTrafficSectionStatisticsService; |
|||
import com.zc.business.statistics.cache.section.DailyTrafficSectionStatisticsCache; |
|||
import com.zc.business.statistics.cache.section.MonthlyTrafficSectionStatisticsCache; |
|||
import com.zc.business.statistics.cache.section.QuarterlyTrafficSectionStatisticsCache; |
|||
import com.zc.business.statistics.cache.section.YearlyTrafficSectionStatisticsCache; |
|||
import com.zc.business.statistics.handler.TrafficSectionAnalysis; |
|||
import com.zc.business.statistics.handler.TrafficSectionStatistics; |
|||
import com.zc.business.utils.StakeMarkUtils; |
|||
import com.zc.common.core.httpclient.exception.HttpException; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import javax.annotation.Resource; |
|||
import java.io.IOException; |
|||
import java.time.Instant; |
|||
import java.time.temporal.ChronoUnit; |
|||
import java.util.*; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 交通断面数据服务实现类,负责处理实时设备消息、缓存数据、定时任务以及数据保存等功能。 |
|||
* |
|||
* @author xiepufeng |
|||
*/ |
|||
@Service |
|||
public class DcTrafficSectionStatisticsServiceImpl |
|||
extends ServiceImpl<DcTrafficSectionDataMapper, DcTrafficSectionData> |
|||
implements IDcTrafficSectionStatisticsService { |
|||
|
|||
// 日志记录器
|
|||
protected final Logger logger = LoggerFactory.getLogger(this.getClass()); |
|||
|
|||
@Resource |
|||
private RedisCache redisCache; |
|||
|
|||
@Resource |
|||
private DcDeviceController dcDeviceController; |
|||
|
|||
@Resource |
|||
private TrafficSectionStatistics trafficSectionStatistics; |
|||
|
|||
@Resource |
|||
private TrafficSectionAnalysis trafficSectionAnalysis; |
|||
|
|||
/** |
|||
* 初始化方法,用于在对象创建后恢复各种周期的交通数据缓存。 |
|||
* 该方法标注了@PostConstruct注解,确保在依赖注入完成后调用。 |
|||
*/ |
|||
@PostConstruct |
|||
public void init() { |
|||
recoveryDailyCache(); // 从es中恢复当月交通数据缓存
|
|||
recoveryMonthlyCache(); // 恢复每月交通数据缓存
|
|||
recoveryQuarterlyCache(); // 恢复每季度交通数据缓存
|
|||
recoveryYearlyCache(); // 恢复每年交通数据缓存
|
|||
} |
|||
|
|||
/** |
|||
* 处理实时接收到的一类交流站设备消息,并将其转换为交通断面统计数据对象并缓存。 |
|||
* |
|||
* @param msg 设备发送的JSON格式实时消息 |
|||
*/ |
|||
@Override |
|||
public void processRealtimeOneStopMessage(JSONObject msg) { |
|||
|
|||
// 1. 将设备消息转换为交通断面数据统计定义对象
|
|||
List<DcTrafficSectionData> dcTrafficSectionDataList = trafficSectionStatistics.convertToTrafficStatistics(msg, DeviceDataCategoryEnum.REAL_TIME); |
|||
|
|||
if (dcTrafficSectionDataList != null && !dcTrafficSectionDataList.isEmpty()) { |
|||
// 2. 添加到缓存中
|
|||
dcTrafficSectionDataList.forEach(this::addCacheData); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取当前的交通截面数据。 |
|||
* |
|||
* @param request 包含获取交通截面所需的所有请求参数的对象。 |
|||
* @return DcTrafficSectionData 返回一个包含当前交通截面数据列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcTrafficSectionData> currentSections(DcTrafficSectionDataRequest request) { |
|||
|
|||
// 从Redis缓存中获取指定方向的交通路段数据列表
|
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches = getDcTrafficSectionDataRedisCache(request.getDirection()); |
|||
|
|||
return filterTrafficDataByRequest(request, dcTrafficSectionDataCaches); |
|||
} |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取历史的交通截面数据。 |
|||
* |
|||
* @param request 包含获取交通截面所需的所有请求参数的对象。 |
|||
* @return DcTrafficSectionData 返回一个包含历史交通截面数据列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcTrafficSectionData> historySections(DcTrafficSectionDataRequest request) { |
|||
|
|||
if (request.getStartTime() == null || request.getEndTime() == null) { |
|||
throw new ServiceException("开始时间或结束时间不能为空"); |
|||
} |
|||
|
|||
if (request.getPeriodType() == null) { |
|||
throw new ServiceException("时段类型不能为空"); |
|||
} |
|||
|
|||
// 构建查询条件
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, request.getStartTime(), request.getEndTime()); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, request.getPeriodType()); |
|||
|
|||
if (request.getDirection() != null) { |
|||
queryWrapper.eq(DcTrafficSectionData::getDirection, request.getDirection()); |
|||
} |
|||
|
|||
if (request.getDeviceType() != null) { |
|||
queryWrapper.eq(DcTrafficSectionData::getDeviceType, request.getDeviceType()); |
|||
} |
|||
|
|||
if (request.getDeviceId() != null) { |
|||
queryWrapper.eq(DcTrafficSectionData::getDeviceId, request.getDeviceId()); |
|||
} |
|||
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
/** |
|||
* 根据请求获取当前交通指标数据。 |
|||
* |
|||
* @param request 包含获取交通指标所需的所有请求参数的对象。 |
|||
* @return 返回当前交通指标数据。 |
|||
* @throws ServiceException 如果没有获取到交通数据,则抛出异常。 |
|||
*/ |
|||
@Override |
|||
public List<DcTrafficMetricsData> currentTrafficMetrics(DcTrafficMetricsDataRequest request) { |
|||
|
|||
// 从Redis缓存中获取指定方向的交通路段数据列表
|
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches = getDcTrafficSectionDataRedisCache(request.getDirection()); |
|||
|
|||
// 过滤掉时间错误的交通数据
|
|||
processStaleTrafficSectionData(dcTrafficSectionDataCaches); |
|||
|
|||
// 根据请求过滤交通数据
|
|||
List<DcTrafficSectionData> trafficSectionDataList = filterTrafficDataByRequest(request, dcTrafficSectionDataCaches); |
|||
|
|||
// 对获取的交通路段数据进行分析,得到交通指标数据
|
|||
List<DcTrafficMetricsData> dcTrafficMetricsDataList = trafficSectionAnalysis.calculateTrafficMetrics(request, trafficSectionDataList); |
|||
|
|||
if (dcTrafficMetricsDataList == null || dcTrafficMetricsDataList.isEmpty()) { |
|||
// 如果没有获取到数据,则抛出异常
|
|||
throw new ServiceException("获取当前交通特征指数失败"); |
|||
} |
|||
|
|||
// 根据收集到的交通段数据计算并返回交通指标数据
|
|||
return dcTrafficMetricsDataList; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 计算获取指定条件下的历史交通指标数据。 |
|||
* |
|||
* @param request 包含查询条件的请求对象,包括开始时间、结束时间、方向、周期类型和所属路段ID等信息。 |
|||
* @return 返回一个包含交通指标数据的列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcTrafficMetricsData> historyTrafficMetrics(DcTrafficMetricsDataRequest request) { |
|||
|
|||
if (request.getStartTime() == null || request.getEndTime() == null) { |
|||
throw new ServiceException("开始时间或结束时间不能为空"); |
|||
} |
|||
|
|||
if (request.getPeriodType() == null) { |
|||
throw new ServiceException("时段类型不能为空"); |
|||
} |
|||
|
|||
// 构建查询条件
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, request.getStartTime(), request.getEndTime()); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, request.getPeriodType()); |
|||
|
|||
if (request.getDirection() != null) { |
|||
queryWrapper.eq(DcTrafficSectionData::getDirection, request.getDirection()); |
|||
} |
|||
|
|||
// 根据请求获取所属路段ID,并进一步筛选路段范围内的数据
|
|||
Long roadSectionId = request.getRoadSectionId(); |
|||
|
|||
if (roadSectionId != null) { |
|||
// 从缓存中获取路段信息,并根据路段的起止桩号筛选数据
|
|||
DcRoadSection dcRoadSection = redisCache.getCacheMapValue(RedisKeyConstants.DC_ROAD_SECTION, roadSectionId); |
|||
if (dcRoadSection != null) { |
|||
queryWrapper.between( |
|||
DcTrafficSectionData::getStakeMark, |
|||
StakeMarkUtils.stakeMarkToInt(dcRoadSection.getStartStakeMark()), |
|||
StakeMarkUtils.stakeMarkToInt(dcRoadSection.getEndStakeMark())); |
|||
} |
|||
} |
|||
|
|||
// 获取设备类型
|
|||
Integer deviceType = request.getDeviceType(); |
|||
|
|||
if (deviceType == null) { |
|||
// 如果没有指定设备类型,则默认为毫米波雷达
|
|||
deviceType = DeviceTypeConstants.MILLIMETER_WAVE_RADAR; |
|||
} |
|||
|
|||
queryWrapper.eq(DcTrafficSectionData::getDeviceType, deviceType); |
|||
|
|||
// 根据收集到的交通段数据计算并返回交通指标数据
|
|||
return trafficSectionAnalysis.calculateTrafficMetrics(request, list(queryWrapper)); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取当前拥堵的路段数据列表。 |
|||
* |
|||
* @param direction 指定的方向,用于筛选交通数据。 |
|||
* @return 返回一个包含当前拥堵路段数据的列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcCongestedSectionData> currentCongestedSection(Byte direction) { |
|||
|
|||
// 从Redis缓存中获取指定方向的交通路段数据列表
|
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches = getDcTrafficSectionDataRedisCache(direction); |
|||
|
|||
// 过滤掉时间错误的交通数据
|
|||
processStaleTrafficSectionData(dcTrafficSectionDataCaches); |
|||
|
|||
// 移除非毫米波雷达设备类型的交通数据
|
|||
dcTrafficSectionDataCaches.removeIf(data -> !Objects.equals(data.getDeviceType(), DeviceTypeConstants.MILLIMETER_WAVE_RADAR)); |
|||
|
|||
// 分析交通数据,计算出当前拥堵的路段列表并返回
|
|||
return trafficSectionAnalysis.calculateCongestedSection(dcTrafficSectionDataCaches); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每日缓存的函数。 |
|||
* 该方法尝试从物联平台获取所有设备信息,并对这些信息进行处理。 |
|||
* 如果获取信息失败或处理过程中发生异常,则记录错误信息。 |
|||
*/ |
|||
private void recoveryDailyCache() { |
|||
|
|||
try { |
|||
// 尝试从指定产品ID获取设备信息
|
|||
Map<String, Object> oneStopDeviceMap = dcDeviceController.getDeviceByProductId(IotProductEnum.ONE_STOP_PRODUCT.value()); |
|||
|
|||
// 检查获取的设备信息是否为空
|
|||
if (oneStopDeviceMap == null || oneStopDeviceMap.get("data") == null) { |
|||
logger.error("获取一类交通量调查站设备数据失败,产品id:{}", IotProductEnum.ONE_STOP_PRODUCT.value()); |
|||
return; |
|||
} |
|||
|
|||
// 将获取的设备信息转换为JSON数组,并遍历处理每个设备的数据
|
|||
JSONArray deviceJsonArray = JSONArray.parseArray(oneStopDeviceMap.get("data").toString()); |
|||
deviceJsonArray.forEach(trafficSectionStatistics::processDeviceData); |
|||
|
|||
} catch (HttpException | IOException e) { |
|||
// 记录处理设备数据时发生的异常
|
|||
logger.error("处理设备数据时发生异常", e); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 恢复每月交通数据缓存的方法。 |
|||
* 通过查询当前月份至今的每日交通数据,并将其添加到每月交通统计缓存中。 |
|||
*/ |
|||
private void recoveryMonthlyCache() { |
|||
// 构建查询条件,查询当前月份至今的每日交通数据
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, TrafficDataPeriodTypeEnum.DAY); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, DateUtil.beginOfMonth(new Date()), new Date()); |
|||
List<DcTrafficSectionData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每日数据添加到每月交通统计缓存
|
|||
dcTrafficSectionDataList.forEach(MonthlyTrafficSectionStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每季度交通数据缓存的方法。 |
|||
* 通过查询当前季度至今的每月交通数据,并将其添加到每季度交通统计缓存中。 |
|||
*/ |
|||
private void recoveryQuarterlyCache() { |
|||
// 构建查询条件,查询当前季度至今的每月交通数据
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, TrafficDataPeriodTypeEnum.MONTH); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, DateUtil.beginOfQuarter(new Date()), new Date()); |
|||
List<DcTrafficSectionData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每月数据添加到每季度交通统计缓存
|
|||
dcTrafficSectionDataList.forEach(QuarterlyTrafficSectionStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每年交通数据缓存的方法。 |
|||
* 通过查询当前年份至今的每季度交通数据,并将其添加到每年交通统计缓存中。 |
|||
*/ |
|||
private void recoveryYearlyCache() { |
|||
// 构建查询条件,查询当前年份至今的每季度交通数据
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, TrafficDataPeriodTypeEnum.QUARTER); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, DateUtil.beginOfYear(new Date()), new Date()); |
|||
List<DcTrafficSectionData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每季度数据添加到每年交通统计缓存
|
|||
dcTrafficSectionDataList.forEach(YearlyTrafficSectionStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 将交通数据添加到缓存中。 |
|||
* 该方法将交通数据既添加到日交通数据缓存中,也实时缓存到Redis中。 |
|||
* |
|||
* @param dcTrafficSectionData 交通段数据对象,包含交通数据的详细信息。 |
|||
*/ |
|||
private void addCacheData(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 添加到日交通数据缓存中
|
|||
DailyTrafficSectionStatisticsCache.addCacheData(dcTrafficSectionData); |
|||
|
|||
// 将数据缓存到redis中
|
|||
redisCache.setCacheMapValue(RedisKeyConstants.getDcDevicesTrafficStatisticsKey(dcTrafficSectionData.getDirection()), |
|||
dcTrafficSectionData.getDeviceId(), |
|||
dcTrafficSectionData); |
|||
} |
|||
|
|||
/** |
|||
* 从Redis缓存中获取指定方向的交通路段数据列表。 |
|||
* |
|||
* @param direction 交通方向,如果为null,则获取双向数据 |
|||
* @return DcTrafficSectionData列表,确保列表非空 |
|||
*/ |
|||
public List<DcTrafficSectionData> getDcTrafficSectionDataRedisCache(Byte direction) { |
|||
|
|||
Map<String, DcTrafficSectionData> dcTrafficSectionDataMap = new HashMap<>(); |
|||
|
|||
// 根据方向选择相应的交通数据
|
|||
Map<String, DcTrafficSectionData> trafficDataMap = (direction != null) |
|||
? getTrafficDataByDirection(direction) |
|||
: getTrafficDataForBothDirections(); |
|||
|
|||
// 将获取的交通数据合并到结果映射中
|
|||
if (trafficDataMap != null) { |
|||
dcTrafficSectionDataMap.putAll(trafficDataMap); |
|||
} |
|||
|
|||
// 将结果映射的值转换为列表并返回,确保列表非空
|
|||
return new ArrayList<>(dcTrafficSectionDataMap.values()); |
|||
} |
|||
|
|||
/** |
|||
* 过滤掉时间错误的交通路段数据,并更新数据的统计时间为当前时间。 |
|||
* 该方法会遍历交通路段数据列表,移除统计时间早于20分钟前的数据,并将其它数据的统计时间更新为当前时间。 |
|||
* |
|||
* @param dcTrafficSectionDataList 交通路段数据列表,列表中每一项包含一个交通路段的统计数据。 |
|||
*/ |
|||
public void processStaleTrafficSectionData(List<DcTrafficSectionData> dcTrafficSectionDataList) { |
|||
// 计算20分钟前的时间戳
|
|||
Instant twentyMinutesAgo = Instant.now().minus(20, ChronoUnit.MINUTES); |
|||
// 获取当前时间
|
|||
Instant currentTime = Instant.now(); |
|||
|
|||
// 遍历交通路段数据列表
|
|||
dcTrafficSectionDataList.removeIf(data -> { |
|||
// 获取数据的统计时间
|
|||
Instant dataStatisticalTime = data.getStatisticalDate().toInstant(); |
|||
|
|||
// 如果数据的统计时间早于20分钟前,则移除该数据,并记录日志
|
|||
if (dataStatisticalTime.isBefore(twentyMinutesAgo)) { |
|||
logger.error("过滤掉时间错误的交通路段数据,已移除:" + data); |
|||
return true; // 移除该元素
|
|||
} |
|||
|
|||
// 更新数据的统计时间为当前时间
|
|||
data.setStatisticalDate(Date.from(currentTime)); // 直接使用Instant对象
|
|||
return false; // 保留该元素
|
|||
}); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 根据方向获取交通数据 |
|||
* |
|||
* @param direction 方向 |
|||
* @return 单向交通数据 |
|||
*/ |
|||
private Map<String, DcTrafficSectionData> getTrafficDataByDirection(Byte direction) { |
|||
return redisCache.getCacheMapValue(RedisKeyConstants.getDcDevicesTrafficStatisticsKey(direction)); |
|||
} |
|||
|
|||
/** |
|||
* 获取上行和下行所有交通数据 |
|||
* |
|||
* @return 所有交通数据 |
|||
*/ |
|||
private Map<String, DcTrafficSectionData> getTrafficDataForBothDirections() { |
|||
Map<String, DcTrafficSectionData> allData = new HashMap<>(); |
|||
allData.putAll(redisCache.getCacheMapValue(RedisKeyConstants.getDcDevicesTrafficStatisticsKey(LaneDirectionEnum.UPWARD.getValue()))); |
|||
allData.putAll(redisCache.getCacheMapValue(RedisKeyConstants.getDcDevicesTrafficStatisticsKey(LaneDirectionEnum.DOWNWARD.getValue()))); |
|||
return allData; |
|||
} |
|||
|
|||
/** |
|||
* 根据请求过滤交通数据。 |
|||
* |
|||
* @param request 包含交通数据查询条件的请求对象,可以指定路段ID和设备类型。 |
|||
* @param dcTrafficSectionDataCaches 存储的交通数据段列表。 |
|||
* @return 过滤后的交通数据段列表,仅包含满足请求条件的数据。 |
|||
*/ |
|||
public List<DcTrafficSectionData> filterTrafficDataByRequest( |
|||
DcTrafficMetricsDataRequest request, |
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches |
|||
) { |
|||
|
|||
if (request == null) { |
|||
return dcTrafficSectionDataCaches; // 如果请求对象为空,直接返回原始交通数据列表
|
|||
} |
|||
|
|||
Long roadSectionId = request.getRoadSectionId(); |
|||
|
|||
// 初始化路段起始和终止桩号
|
|||
Integer startStakeMark = null; |
|||
Integer endStakeMark = null; |
|||
|
|||
if (roadSectionId != null) { |
|||
// 根据提供的路段ID查询路段信息,并转换为起始和终止桩号
|
|||
DcRoadSection dcRoadSection = redisCache.getCacheMapValue(RedisKeyConstants.DC_ROAD_SECTION, roadSectionId); |
|||
|
|||
// 验证路段ID是否存在
|
|||
if (dcRoadSection == null) { |
|||
throw new ServiceException("路段ID不存在"); |
|||
} |
|||
|
|||
startStakeMark = StakeMarkUtils.stakeMarkToInt(dcRoadSection.getStartStakeMark()); |
|||
endStakeMark = StakeMarkUtils.stakeMarkToInt(dcRoadSection.getEndStakeMark()); |
|||
} |
|||
|
|||
// 获取请求中的设备类型
|
|||
Integer deviceType = request.getDeviceType(); |
|||
|
|||
// 如果设备类型为空,则默认为毫米波雷达
|
|||
if (deviceType == null) { |
|||
deviceType = DeviceTypeConstants.MILLIMETER_WAVE_RADAR; |
|||
} |
|||
|
|||
// 使用lambda表达式和流对交通数据进行过滤
|
|||
final Integer finalStartStakeMark = startStakeMark; |
|||
final Integer finalEndStakeMark = endStakeMark; |
|||
final Integer finalDeviceType = deviceType; |
|||
|
|||
// 筛选并返回符合路段范围条件和设备类型条件的交通数据列表
|
|||
return dcTrafficSectionDataCaches.stream() |
|||
.filter(data -> (finalStartStakeMark == null || finalEndStakeMark == null |
|||
|| (data.getStakeMark() >= finalStartStakeMark && data.getStakeMark() <= finalEndStakeMark)) |
|||
&& finalDeviceType.equals(data.getDeviceType())) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
|
|||
/** |
|||
* 根据请求过滤交通数据。 |
|||
* |
|||
* @param request 包含设备类型和设备ID的请求对象,用于指定过滤条件。 |
|||
* @param dcTrafficSectionDataCaches 原始的交通数据列表。 |
|||
* @return 过滤后的交通数据列表,仅包含与请求条件匹配的数据。 |
|||
*/ |
|||
public List<DcTrafficSectionData> filterTrafficDataByRequest( |
|||
DcTrafficSectionDataRequest request, |
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches |
|||
) { |
|||
|
|||
if (request == null) { |
|||
return dcTrafficSectionDataCaches; // 如果请求对象为空,直接返回原始交通数据列表
|
|||
} |
|||
|
|||
Integer deviceType = request.getDeviceType(); |
|||
Long deviceId = request.getDeviceId(); |
|||
|
|||
if (deviceType == null && deviceId == null) { |
|||
return dcTrafficSectionDataCaches; // 如果请求中既没有设备类型也没有设备ID,返回原始数据列表
|
|||
} |
|||
|
|||
// 使用流对交通数据进行过滤,只返回与请求中的设备类型和设备ID匹配的数据
|
|||
return dcTrafficSectionDataCaches.stream() |
|||
.filter(data -> { |
|||
boolean typeMatches = deviceType == null || data.getDeviceType().equals(deviceType); // 设备类型匹配条件
|
|||
boolean idMatches = deviceId == null || data.getDeviceId().equals(deviceId); // 设备ID匹配条件
|
|||
return typeMatches && idMatches; // 只有当两者都匹配时,数据才被保留
|
|||
}) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -1,508 +1,23 @@ |
|||
package com.zc.business.service.impl; |
|||
|
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.alibaba.fastjson.JSONArray; |
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.ruoyi.common.core.redis.RedisCache; |
|||
import com.ruoyi.common.exception.ServiceException; |
|||
import com.zc.business.constant.DeviceTypeConstants; |
|||
import com.zc.business.constant.RedisKeyConstants; |
|||
import com.zc.business.controller.DcDeviceController; |
|||
import com.zc.business.domain.DcCongestedSectionData; |
|||
import com.zc.business.domain.DcRoadSection; |
|||
import com.zc.business.domain.DcTrafficMetricsData; |
|||
import com.zc.business.domain.DcTrafficSectionData; |
|||
import com.zc.business.enums.*; |
|||
import com.zc.business.request.DcTrafficMetricsDataRequest; |
|||
import com.zc.business.request.DcTrafficSectionDataRequest; |
|||
import com.zc.business.statistics.cache.*; |
|||
import com.zc.business.mapper.DcTrafficSectionDataMapper; |
|||
import com.zc.business.domain.DcStatisticsData; |
|||
import com.zc.business.service.IDcTrafficStatisticsService; |
|||
import com.zc.business.statistics.handler.TrafficAnalysis; |
|||
import com.zc.business.statistics.handler.TrafficStatistics; |
|||
import com.zc.business.utils.StakeMarkUtils; |
|||
import com.zc.common.core.httpclient.exception.HttpException; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import javax.annotation.Resource; |
|||
import java.io.IOException; |
|||
import java.time.Instant; |
|||
import java.time.temporal.ChronoUnit; |
|||
import java.util.*; |
|||
import java.util.stream.Collectors; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 交通断面数据服务实现类,负责处理实时设备消息、缓存数据、定时任务以及数据保存等功能。 |
|||
* |
|||
* @author xiepufeng |
|||
*/ |
|||
@Service |
|||
public class DcTrafficStatisticsServiceImpl |
|||
extends ServiceImpl<DcTrafficSectionDataMapper, DcTrafficSectionData> |
|||
implements IDcTrafficStatisticsService { |
|||
|
|||
// 日志记录器
|
|||
protected final Logger logger = LoggerFactory.getLogger(this.getClass()); |
|||
|
|||
@Resource |
|||
private RedisCache redisCache; |
|||
|
|||
@Resource |
|||
private DcDeviceController dcDeviceController; |
|||
|
|||
@Resource |
|||
private TrafficStatistics trafficStatistics; |
|||
|
|||
@Resource |
|||
private TrafficAnalysis trafficAnalysis; |
|||
|
|||
/** |
|||
* 初始化方法,用于在对象创建后恢复各种周期的交通数据缓存。 |
|||
* 该方法标注了@PostConstruct注解,确保在依赖注入完成后调用。 |
|||
*/ |
|||
@PostConstruct |
|||
public void init() { |
|||
recoveryDailyCache(); // 从es中恢复当天交通数据缓存
|
|||
recoveryMonthlyCache(); // 恢复每月交通数据缓存
|
|||
recoveryQuarterlyCache(); // 恢复每季度交通数据缓存
|
|||
recoveryYearlyCache(); // 恢复每年交通数据缓存
|
|||
} |
|||
|
|||
/** |
|||
* 处理实时接收到的一类交流站设备消息,并将其转换为交通断面统计数据对象并缓存。 |
|||
* |
|||
* @param msg 设备发送的JSON格式实时消息 |
|||
*/ |
|||
@Override |
|||
public void processRealtimeOneStopMessage(JSONObject msg) { |
|||
|
|||
// 1. 将设备消息转换为交通断面数据统计定义对象
|
|||
List<DcTrafficSectionData> dcTrafficSectionDataList = trafficStatistics.convertToTrafficStatistics(msg, DeviceDataCategoryEnum.REAL_TIME); |
|||
|
|||
if (dcTrafficSectionDataList != null && !dcTrafficSectionDataList.isEmpty()) { |
|||
// 2. 添加到缓存中
|
|||
dcTrafficSectionDataList.forEach(this::addCacheData); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取当前的交通截面数据。 |
|||
* |
|||
* @param request 包含获取交通截面所需的所有请求参数的对象。 |
|||
* @return DcTrafficSectionData 返回一个包含当前交通截面数据列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcTrafficSectionData> currentSections(DcTrafficSectionDataRequest request) { |
|||
|
|||
// 从Redis缓存中获取指定方向的交通路段数据列表
|
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches = getDcTrafficSectionDataRedisCache(request.getDirection()); |
|||
|
|||
return filterTrafficDataByRequest(request, dcTrafficSectionDataCaches); |
|||
} |
|||
|
|||
/** |
|||
* 根据提供的请求参数获取历史的交通截面数据。 |
|||
* |
|||
* @param request 包含获取交通截面所需的所有请求参数的对象。 |
|||
* @return DcTrafficSectionData 返回一个包含历史交通截面数据列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcTrafficSectionData> historySections(DcTrafficSectionDataRequest request) { |
|||
|
|||
if (request.getStartTime() == null || request.getEndTime() == null) { |
|||
throw new ServiceException("开始时间或结束时间不能为空"); |
|||
} |
|||
|
|||
if (request.getPeriodType() == null) { |
|||
throw new ServiceException("时段类型不能为空"); |
|||
} |
|||
|
|||
// 构建查询条件
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, request.getStartTime(), request.getEndTime()); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, request.getPeriodType()); |
|||
|
|||
if (request.getDirection() != null) { |
|||
queryWrapper.eq(DcTrafficSectionData::getDirection, request.getDirection()); |
|||
} |
|||
|
|||
if (request.getDeviceType() != null) { |
|||
queryWrapper.eq(DcTrafficSectionData::getDeviceType, request.getDeviceType()); |
|||
} |
|||
|
|||
if (request.getDeviceId() != null) { |
|||
queryWrapper.eq(DcTrafficSectionData::getDeviceId, request.getDeviceId()); |
|||
} |
|||
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
/** |
|||
* 根据请求获取当前交通指标数据。 |
|||
* |
|||
* @param request 包含获取交通指标所需的所有请求参数的对象。 |
|||
* @return 返回当前交通指标数据。 |
|||
* @throws ServiceException 如果没有获取到交通数据,则抛出异常。 |
|||
*/ |
|||
@Override |
|||
public List<DcTrafficMetricsData> currentTrafficMetrics(DcTrafficMetricsDataRequest request) { |
|||
|
|||
// 从Redis缓存中获取指定方向的交通路段数据列表
|
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches = getDcTrafficSectionDataRedisCache(request.getDirection()); |
|||
|
|||
// 过滤掉时间错误的交通数据
|
|||
processStaleTrafficSectionData(dcTrafficSectionDataCaches); |
|||
|
|||
// 根据请求过滤交通数据
|
|||
List<DcTrafficSectionData> trafficSectionDataList = filterTrafficDataByRequest(request, dcTrafficSectionDataCaches); |
|||
|
|||
// 对获取的交通路段数据进行分析,得到交通指标数据
|
|||
List<DcTrafficMetricsData> dcTrafficMetricsDataList = trafficAnalysis.calculateTrafficMetrics(request, trafficSectionDataList); |
|||
|
|||
if (dcTrafficMetricsDataList == null || dcTrafficMetricsDataList.isEmpty()) { |
|||
// 如果没有获取到数据,则抛出异常
|
|||
throw new ServiceException("获取当前交通特征指数失败"); |
|||
} |
|||
|
|||
// 根据收集到的交通段数据计算并返回交通指标数据
|
|||
return dcTrafficMetricsDataList; |
|||
} |
|||
|
|||
public class DcTrafficStatisticsServiceImpl implements IDcTrafficStatisticsService { |
|||
|
|||
/** |
|||
* 计算获取指定条件下的历史交通指标数据。 |
|||
* 根据传入的统计请求数据,查询历史累计车流量数据。 |
|||
* |
|||
* @param request 包含查询条件的请求对象,包括开始时间、结束时间、方向、周期类型和所属路段ID等信息。 |
|||
* @return 返回一个包含交通指标数据的列表。 |
|||
* @param request 包含统计查询条件的DcStatisticsData对象,用于指定查询的历史流量数据的细节,如时间范围等。 |
|||
* @return 返回一个DcStatisticsData列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcTrafficMetricsData> historyTrafficMetrics(DcTrafficMetricsDataRequest request) { |
|||
|
|||
if (request.getStartTime() == null || request.getEndTime() == null) { |
|||
throw new ServiceException("开始时间或结束时间不能为空"); |
|||
} |
|||
|
|||
if (request.getPeriodType() == null) { |
|||
throw new ServiceException("时段类型不能为空"); |
|||
} |
|||
|
|||
// 构建查询条件
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, request.getStartTime(), request.getEndTime()); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, request.getPeriodType()); |
|||
|
|||
if (request.getDirection() != null) { |
|||
queryWrapper.eq(DcTrafficSectionData::getDirection, request.getDirection()); |
|||
} |
|||
|
|||
// 根据请求获取所属路段ID,并进一步筛选路段范围内的数据
|
|||
Long roadSectionId = request.getRoadSectionId(); |
|||
|
|||
if (roadSectionId != null) { |
|||
// 从缓存中获取路段信息,并根据路段的起止桩号筛选数据
|
|||
DcRoadSection dcRoadSection = redisCache.getCacheMapValue(RedisKeyConstants.DC_ROAD_SECTION, roadSectionId); |
|||
if (dcRoadSection != null) { |
|||
queryWrapper.between( |
|||
DcTrafficSectionData::getStakeMark, |
|||
StakeMarkUtils.stakeMarkToInt(dcRoadSection.getStartStakeMark()), |
|||
StakeMarkUtils.stakeMarkToInt(dcRoadSection.getEndStakeMark())); |
|||
} |
|||
} |
|||
|
|||
// 获取设备类型
|
|||
Integer deviceType = request.getDeviceType(); |
|||
|
|||
if (deviceType == null) { |
|||
// 如果没有指定设备类型,则默认为毫米波雷达
|
|||
deviceType = DeviceTypeConstants.MILLIMETER_WAVE_RADAR; |
|||
} |
|||
|
|||
queryWrapper.eq(DcTrafficSectionData::getDeviceType, deviceType); |
|||
|
|||
// 根据收集到的交通段数据计算并返回交通指标数据
|
|||
return trafficAnalysis.calculateTrafficMetrics(request, list(queryWrapper)); |
|||
public List<DcStatisticsData> historyFlow(DcStatisticsData request) { |
|||
// TODO
|
|||
return null; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取当前拥堵的路段数据列表。 |
|||
* |
|||
* @param direction 指定的方向,用于筛选交通数据。 |
|||
* @return 返回一个包含当前拥堵路段数据的列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcCongestedSectionData> currentCongestedSection(Byte direction) { |
|||
|
|||
// 从Redis缓存中获取指定方向的交通路段数据列表
|
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches = getDcTrafficSectionDataRedisCache(direction); |
|||
|
|||
// 过滤掉时间错误的交通数据
|
|||
processStaleTrafficSectionData(dcTrafficSectionDataCaches); |
|||
|
|||
// 移除非毫米波雷达设备类型的交通数据
|
|||
dcTrafficSectionDataCaches.removeIf(data -> !Objects.equals(data.getDeviceType(), DeviceTypeConstants.MILLIMETER_WAVE_RADAR)); |
|||
|
|||
// 分析交通数据,计算出当前拥堵的路段列表并返回
|
|||
return trafficAnalysis.calculateCongestedSection(dcTrafficSectionDataCaches); |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 恢复每日缓存的函数。 |
|||
* 该方法尝试从物联平台获取所有设备信息,并对这些信息进行处理。 |
|||
* 如果获取信息失败或处理过程中发生异常,则记录错误信息。 |
|||
*/ |
|||
private void recoveryDailyCache() { |
|||
|
|||
try { |
|||
// 尝试从指定产品ID获取设备信息
|
|||
Map<String, Object> oneStopDeviceMap = dcDeviceController.getDeviceByProductId(IotProductEnum.ONE_STOP_PRODUCT.value()); |
|||
|
|||
// 检查获取的设备信息是否为空
|
|||
if (oneStopDeviceMap == null || oneStopDeviceMap.get("data") == null) { |
|||
logger.error("获取一类交通量调查站设备数据失败,产品id:{}", IotProductEnum.ONE_STOP_PRODUCT.value()); |
|||
return; |
|||
} |
|||
|
|||
// 将获取的设备信息转换为JSON数组,并遍历处理每个设备的数据
|
|||
JSONArray deviceJsonArray = JSONArray.parseArray(oneStopDeviceMap.get("data").toString()); |
|||
deviceJsonArray.forEach(trafficStatistics::processDeviceData); |
|||
|
|||
} catch (HttpException | IOException e) { |
|||
// 记录处理设备数据时发生的异常
|
|||
logger.error("处理设备数据时发生异常", e); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 恢复每月交通数据缓存的方法。 |
|||
* 通过查询当前月份至今的每日交通数据,并将其添加到每月交通统计缓存中。 |
|||
*/ |
|||
private void recoveryMonthlyCache() { |
|||
// 构建查询条件,查询当前月份至今的每日交通数据
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, TrafficDataPeriodTypeEnum.DAY); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, DateUtil.beginOfMonth(new Date()), new Date()); |
|||
List<DcTrafficSectionData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每日数据添加到每月交通统计缓存
|
|||
dcTrafficSectionDataList.forEach(MonthlyTrafficStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每季度交通数据缓存的方法。 |
|||
* 通过查询当前季度至今的每月交通数据,并将其添加到每季度交通统计缓存中。 |
|||
*/ |
|||
private void recoveryQuarterlyCache() { |
|||
// 构建查询条件,查询当前季度至今的每月交通数据
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, TrafficDataPeriodTypeEnum.MONTH); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, DateUtil.beginOfQuarter(new Date()), new Date()); |
|||
List<DcTrafficSectionData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每月数据添加到每季度交通统计缓存
|
|||
dcTrafficSectionDataList.forEach(QuarterlyTrafficStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 恢复每年交通数据缓存的方法。 |
|||
* 通过查询当前年份至今的每季度交通数据,并将其添加到每年交通统计缓存中。 |
|||
*/ |
|||
private void recoveryYearlyCache() { |
|||
// 构建查询条件,查询当前年份至今的每季度交通数据
|
|||
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(DcTrafficSectionData::getPeriodType, TrafficDataPeriodTypeEnum.QUARTER); |
|||
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, DateUtil.beginOfYear(new Date()), new Date()); |
|||
List<DcTrafficSectionData> dcTrafficSectionDataList = this.list(queryWrapper); |
|||
// 遍历查询结果,将每季度数据添加到每年交通统计缓存
|
|||
dcTrafficSectionDataList.forEach(YearlyTrafficStatisticsCache::addCacheData); |
|||
} |
|||
|
|||
/** |
|||
* 将交通数据添加到缓存中。 |
|||
* 该方法将交通数据既添加到日交通数据缓存中,也实时缓存到Redis中。 |
|||
* |
|||
* @param dcTrafficSectionData 交通段数据对象,包含交通数据的详细信息。 |
|||
*/ |
|||
private void addCacheData(DcTrafficSectionData dcTrafficSectionData) { |
|||
// 添加到日交通数据缓存中
|
|||
DailyTrafficStatisticsCache.addCacheData(dcTrafficSectionData); |
|||
|
|||
// 将数据缓存到redis中
|
|||
redisCache.setCacheMapValue(RedisKeyConstants.getDcDevicesTrafficStatisticsKey(dcTrafficSectionData.getDirection()), |
|||
dcTrafficSectionData.getDeviceId(), |
|||
dcTrafficSectionData); |
|||
} |
|||
|
|||
/** |
|||
* 从Redis缓存中获取指定方向的交通路段数据列表。 |
|||
* |
|||
* @param direction 交通方向,如果为null,则获取双向数据 |
|||
* @return DcTrafficSectionData列表,确保列表非空 |
|||
*/ |
|||
public List<DcTrafficSectionData> getDcTrafficSectionDataRedisCache(Byte direction) { |
|||
|
|||
Map<String, DcTrafficSectionData> dcTrafficSectionDataMap = new HashMap<>(); |
|||
|
|||
// 根据方向选择相应的交通数据
|
|||
Map<String, DcTrafficSectionData> trafficDataMap = (direction != null) |
|||
? getTrafficDataByDirection(direction) |
|||
: getTrafficDataForBothDirections(); |
|||
|
|||
// 将获取的交通数据合并到结果映射中
|
|||
if (trafficDataMap != null) { |
|||
dcTrafficSectionDataMap.putAll(trafficDataMap); |
|||
} |
|||
|
|||
// 将结果映射的值转换为列表并返回,确保列表非空
|
|||
return new ArrayList<>(dcTrafficSectionDataMap.values()); |
|||
} |
|||
|
|||
/** |
|||
* 过滤掉时间错误的交通路段数据,并更新数据的统计时间为当前时间。 |
|||
* 该方法会遍历交通路段数据列表,移除统计时间早于20分钟前的数据,并将其它数据的统计时间更新为当前时间。 |
|||
* |
|||
* @param dcTrafficSectionDataList 交通路段数据列表,列表中每一项包含一个交通路段的统计数据。 |
|||
*/ |
|||
public void processStaleTrafficSectionData(List<DcTrafficSectionData> dcTrafficSectionDataList) { |
|||
// 计算20分钟前的时间戳
|
|||
Instant twentyMinutesAgo = Instant.now().minus(20, ChronoUnit.MINUTES); |
|||
// 获取当前时间
|
|||
Instant currentTime = Instant.now(); |
|||
|
|||
// 遍历交通路段数据列表
|
|||
dcTrafficSectionDataList.removeIf(data -> { |
|||
// 获取数据的统计时间
|
|||
Instant dataStatisticalTime = data.getStatisticalDate().toInstant(); |
|||
|
|||
// 如果数据的统计时间早于20分钟前,则移除该数据,并记录日志
|
|||
if (dataStatisticalTime.isBefore(twentyMinutesAgo)) { |
|||
logger.error("过滤掉时间错误的交通路段数据,已移除:" + data); |
|||
return true; // 移除该元素
|
|||
} |
|||
|
|||
// 更新数据的统计时间为当前时间
|
|||
data.setStatisticalDate(Date.from(currentTime)); // 直接使用Instant对象
|
|||
return false; // 保留该元素
|
|||
}); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 根据方向获取交通数据 |
|||
* |
|||
* @param direction 方向 |
|||
* @return 单向交通数据 |
|||
*/ |
|||
private Map<String, DcTrafficSectionData> getTrafficDataByDirection(Byte direction) { |
|||
return redisCache.getCacheMapValue(RedisKeyConstants.getDcDevicesTrafficStatisticsKey(direction)); |
|||
} |
|||
|
|||
/** |
|||
* 获取上行和下行所有交通数据 |
|||
* |
|||
* @return 所有交通数据 |
|||
*/ |
|||
private Map<String, DcTrafficSectionData> getTrafficDataForBothDirections() { |
|||
Map<String, DcTrafficSectionData> allData = new HashMap<>(); |
|||
allData.putAll(redisCache.getCacheMapValue(RedisKeyConstants.getDcDevicesTrafficStatisticsKey(LaneDirectionEnum.UPWARD.getValue()))); |
|||
allData.putAll(redisCache.getCacheMapValue(RedisKeyConstants.getDcDevicesTrafficStatisticsKey(LaneDirectionEnum.DOWNWARD.getValue()))); |
|||
return allData; |
|||
} |
|||
|
|||
/** |
|||
* 根据请求过滤交通数据。 |
|||
* |
|||
* @param request 包含交通数据查询条件的请求对象,可以指定路段ID和设备类型。 |
|||
* @param dcTrafficSectionDataCaches 存储的交通数据段列表。 |
|||
* @return 过滤后的交通数据段列表,仅包含满足请求条件的数据。 |
|||
*/ |
|||
public List<DcTrafficSectionData> filterTrafficDataByRequest( |
|||
DcTrafficMetricsDataRequest request, |
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches |
|||
) { |
|||
|
|||
if (request == null) { |
|||
return dcTrafficSectionDataCaches; // 如果请求对象为空,直接返回原始交通数据列表
|
|||
} |
|||
|
|||
Long roadSectionId = request.getRoadSectionId(); |
|||
|
|||
// 初始化路段起始和终止桩号
|
|||
Integer startStakeMark = null; |
|||
Integer endStakeMark = null; |
|||
|
|||
if (roadSectionId != null) { |
|||
// 根据提供的路段ID查询路段信息,并转换为起始和终止桩号
|
|||
DcRoadSection dcRoadSection = redisCache.getCacheMapValue(RedisKeyConstants.DC_ROAD_SECTION, roadSectionId); |
|||
|
|||
// 验证路段ID是否存在
|
|||
if (dcRoadSection == null) { |
|||
throw new ServiceException("路段ID不存在"); |
|||
} |
|||
|
|||
startStakeMark = StakeMarkUtils.stakeMarkToInt(dcRoadSection.getStartStakeMark()); |
|||
endStakeMark = StakeMarkUtils.stakeMarkToInt(dcRoadSection.getEndStakeMark()); |
|||
} |
|||
|
|||
// 获取请求中的设备类型
|
|||
Integer deviceType = request.getDeviceType(); |
|||
|
|||
// 如果设备类型为空,则默认为毫米波雷达
|
|||
if (deviceType == null) { |
|||
deviceType = DeviceTypeConstants.MILLIMETER_WAVE_RADAR; |
|||
} |
|||
|
|||
// 使用lambda表达式和流对交通数据进行过滤
|
|||
final Integer finalStartStakeMark = startStakeMark; |
|||
final Integer finalEndStakeMark = endStakeMark; |
|||
final Integer finalDeviceType = deviceType; |
|||
|
|||
// 筛选并返回符合路段范围条件和设备类型条件的交通数据列表
|
|||
return dcTrafficSectionDataCaches.stream() |
|||
.filter(data -> (finalStartStakeMark == null || finalEndStakeMark == null |
|||
|| (data.getStakeMark() >= finalStartStakeMark && data.getStakeMark() <= finalEndStakeMark)) |
|||
&& finalDeviceType.equals(data.getDeviceType())) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
|
|||
/** |
|||
* 根据请求过滤交通数据。 |
|||
* |
|||
* @param request 包含设备类型和设备ID的请求对象,用于指定过滤条件。 |
|||
* @param dcTrafficSectionDataCaches 原始的交通数据列表。 |
|||
* @return 过滤后的交通数据列表,仅包含与请求条件匹配的数据。 |
|||
*/ |
|||
public List<DcTrafficSectionData> filterTrafficDataByRequest( |
|||
DcTrafficSectionDataRequest request, |
|||
List<DcTrafficSectionData> dcTrafficSectionDataCaches |
|||
) { |
|||
|
|||
if (request == null) { |
|||
return dcTrafficSectionDataCaches; // 如果请求对象为空,直接返回原始交通数据列表
|
|||
} |
|||
|
|||
Integer deviceType = request.getDeviceType(); |
|||
Long deviceId = request.getDeviceId(); |
|||
|
|||
if (deviceType == null && deviceId == null) { |
|||
return dcTrafficSectionDataCaches; // 如果请求中既没有设备类型也没有设备ID,返回原始数据列表
|
|||
} |
|||
|
|||
// 使用流对交通数据进行过滤,只返回与请求中的设备类型和设备ID匹配的数据
|
|||
return dcTrafficSectionDataCaches.stream() |
|||
.filter(data -> { |
|||
boolean typeMatches = deviceType == null || data.getDeviceType().equals(deviceType); // 设备类型匹配条件
|
|||
boolean idMatches = deviceId == null || data.getDeviceId().equals(deviceId); // 设备ID匹配条件
|
|||
return typeMatches && idMatches; // 只有当两者都匹配时,数据才被保留
|
|||
}) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
|
@ -0,0 +1,244 @@ |
|||
package com.zc.business.service.impl; |
|||
|
|||
import cn.hutool.core.date.DateTime; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.ruoyi.common.annotation.DataSource; |
|||
import com.ruoyi.common.enums.DataSourceType; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.domain.OdsTollEnpassData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.enums.VehicleTypeEnum; |
|||
import com.zc.business.mapper.OdsTollEnpassDataMapper; |
|||
import com.zc.business.service.IOdsTollEnpassDataService; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 收费站入口流水数据 |
|||
*/ |
|||
@Service |
|||
@DataSource(value = DataSourceType.SLAVE)//切换数据源
|
|||
public class OdsTollEnpassDataServiceImpl extends ServiceImpl<OdsTollEnpassDataMapper, OdsTollEnpassData> |
|||
implements IOdsTollEnpassDataService { |
|||
|
|||
/** |
|||
* 获取过去一小时的OdsTollEnpassData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含过去一小时所有符合条件的OdsTollEnpassData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollEnpassData> - 过去一小时的OdsTollEnpassData数据列表。 |
|||
*/ |
|||
@Override |
|||
public List<OdsTollEnpassData> lastHourData() { |
|||
// 创建查询条件包装器
|
|||
LambdaQueryWrapper<OdsTollEnpassData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
// 计算一小时前的时间点
|
|||
DateTime lastHour = DateUtil.offsetHour(new Date(), -1); |
|||
// 设置查询条件,查询时间包含在lastHour内的数据
|
|||
queryWrapper.between(OdsTollEnpassData::getEntime, DateUtil.beginOfHour(lastHour), DateUtil.endOfHour(lastHour)); |
|||
// 根据查询条件获取数据列表并返回
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
/** |
|||
* 获取当月的OdsTollEnpassData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含当月所有符合条件的OdsTollEnpassData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollEnpassData> - 当月的OdsTollEnpassData数据列表。 |
|||
*/ |
|||
@Override |
|||
public List<OdsTollEnpassData> currentMonthData() { |
|||
// 创建查询条件包装器
|
|||
LambdaQueryWrapper<OdsTollEnpassData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
// 设置查询条件,查询当前月份的所有数据
|
|||
queryWrapper.between(OdsTollEnpassData::getEntime, DateUtil.beginOfMonth(new Date()), new Date()); |
|||
// 根据查询条件获取数据列表并返回
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 计算收费站在指定时间段内的统计数据。 |
|||
* |
|||
* @param list 包含收费通行数据的列表,不应为null或空。 |
|||
* @return 返回一个包含各收费站统计数据的列表。如果输入列表为空,则返回空列表。 |
|||
*/ |
|||
public List<DcTollStationStatisticsData> calculateTollStationStatistics(List<OdsTollEnpassData> list) { |
|||
|
|||
// 检查输入列表是否为空,如果是则直接返回空列表
|
|||
if (list == null || list.isEmpty()) { |
|||
return new ArrayList<>(); |
|||
} |
|||
|
|||
// 使用Stream API按入口站号和入口时间进行分组
|
|||
Map<String, Map<String, List<OdsTollEnpassData>>> groupedData = |
|||
list.stream() |
|||
.collect(Collectors.groupingBy( |
|||
OdsTollEnpassData::getEntollstationid, // 按入口站号分组
|
|||
Collectors.groupingBy(odsTollEnpassData -> DateUtil.beginOfHour(odsTollEnpassData.getEntime()).toString()) // 在每个入口站内按入口通行时间进一步分组
|
|||
)); |
|||
|
|||
// 遍历分组后的数据,计算每个收费站每个时间周期内的统计数据
|
|||
List<DcTollStationStatisticsData> dcTollStationStatisticsDataList = new ArrayList<>(); |
|||
groupedData.forEach((entollstationid, timeGroupedData) -> timeGroupedData.forEach((entime, dataList) -> dcTollStationStatisticsDataList.add(trafficStatistics(dataList)))); |
|||
|
|||
return dcTollStationStatisticsDataList; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 计算交通统计数据 |
|||
* |
|||
* @param list 包含收费过境数据的列表 |
|||
* @return DcTollStationStatisticsData 对象,包含计算后的交通统计数据 |
|||
*/ |
|||
private DcTollStationStatisticsData trafficStatistics(List<OdsTollEnpassData> list) { |
|||
|
|||
// 创建DcTollStationStatisticsData对象并初始化
|
|||
DcTollStationStatisticsData dcTollStationStatisticsData = new DcTollStationStatisticsData(); |
|||
|
|||
// 初始化车流量总和
|
|||
int trafficVolume = 0; |
|||
|
|||
// 初始化1型客车车流量
|
|||
int type1PassengerFlow = 0; |
|||
// 初始化2型客车车流量
|
|||
int type2PassengerFlow = 0; |
|||
// 初始化3型客车车流量
|
|||
int type3PassengerFlow = 0; |
|||
// 初始化4型客车车流量
|
|||
int type4PassengerFlow = 0; |
|||
|
|||
// 初始化1型货车车流量
|
|||
int type1TruckFlow = 0; |
|||
// 初始化2型货车车流量
|
|||
int type2TruckFlow = 0; |
|||
// 初始化3型货车车流量
|
|||
int type3TruckFlow = 0; |
|||
// 初始化4型货车车流量
|
|||
int type4TruckFlow = 0; |
|||
// 初始化5型货车车流量
|
|||
int type5TruckFlow = 0; |
|||
// 初始化6型货车车流量
|
|||
int type6TruckFlow = 0; |
|||
|
|||
// 初始化1型专项作业车车流量
|
|||
int type1SpecialVehicleFlow = 0; |
|||
// 初始化2型专项作业车车流量
|
|||
int type2SpecialVehicleFlow = 0; |
|||
// 初始化3型专项作业车车流量
|
|||
int type3SpecialVehicleFlow = 0; |
|||
// 初始化4型专项作业车车流量
|
|||
int type4SpecialVehicleFlow = 0; |
|||
// 初始化5型专项作业车车流量
|
|||
int type5SpecialVehicleFlow = 0; |
|||
// 初始化6型专项作业车车流量
|
|||
int type6SpecialVehicleFlow = 0; |
|||
|
|||
for (OdsTollEnpassData odsTollEnpassData : list) { |
|||
Integer vcount = odsTollEnpassData.getVcount(); |
|||
Integer vehicletype = odsTollEnpassData.getVehicletype(); |
|||
|
|||
trafficVolume += vcount; |
|||
|
|||
if (VehicleTypeEnum.TYPE_1_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type1PassengerFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_2_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type2PassengerFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_3_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type3PassengerFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_4_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type4PassengerFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_1_TRUCK.getValue().equals(vehicletype)) { |
|||
type1TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_2_TRUCK.getValue().equals(vehicletype)) { |
|||
type2TruckFlow+= vcount; |
|||
} else if (VehicleTypeEnum.TYPE_3_TRUCK.getValue().equals(vehicletype)) { |
|||
type3TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_4_TRUCK.getValue().equals(vehicletype)) { |
|||
type4TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_5_TRUCK.getValue().equals(vehicletype)) { |
|||
type5TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_6_TRUCK.getValue().equals(vehicletype)) { |
|||
type6TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_1_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type1SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_2_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type2SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_3_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type3SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_4_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type4SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_5_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type5SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_6_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type6SpecialVehicleFlow += vcount; |
|||
} |
|||
} |
|||
|
|||
// 使用第一个数据项的信息填充汇总统计对象的基本属性
|
|||
OdsTollEnpassData firstOdsTollEnpassData = list.iterator().next(); |
|||
|
|||
// 收费站站点标识
|
|||
dcTollStationStatisticsData.setTollStationCode(firstOdsTollEnpassData.getEntollstationid()); |
|||
Date date = DateUtil.beginOfHour(firstOdsTollEnpassData.getEntime()); |
|||
// 统计时间
|
|||
dcTollStationStatisticsData.setStatisticalDate(date); |
|||
// 上报时间
|
|||
dcTollStationStatisticsData.setReportTime(date); |
|||
// 统计粒度
|
|||
dcTollStationStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.DAY); |
|||
// 出入类型
|
|||
dcTollStationStatisticsData.setAccessType(DcTollStationStatisticsData.ENTRANCE); |
|||
|
|||
// 车流量
|
|||
dcTollStationStatisticsData.setTrafficVolume(trafficVolume); |
|||
// 1型客车车流量
|
|||
dcTollStationStatisticsData.setType1PassengerFlow(type1PassengerFlow); |
|||
// 2型客车车流量
|
|||
dcTollStationStatisticsData.setType2PassengerFlow(type2PassengerFlow); |
|||
// 3型客车车流量
|
|||
dcTollStationStatisticsData.setType3PassengerFlow(type3PassengerFlow); |
|||
// 4型客车车流量
|
|||
dcTollStationStatisticsData.setType4PassengerFlow(type4PassengerFlow); |
|||
// 1型货车车流量
|
|||
dcTollStationStatisticsData.setType1TruckFlow(type1TruckFlow); |
|||
// 2型货车车流量
|
|||
dcTollStationStatisticsData.setType2TruckFlow(type2TruckFlow); |
|||
// 3型货车车流量
|
|||
dcTollStationStatisticsData.setType3TruckFlow(type3TruckFlow); |
|||
// 4型货车车流量
|
|||
dcTollStationStatisticsData.setType4TruckFlow(type4TruckFlow); |
|||
// 5型货车车流量
|
|||
dcTollStationStatisticsData.setType5TruckFlow(type5TruckFlow); |
|||
// 6型货车车流量
|
|||
dcTollStationStatisticsData.setType6TruckFlow(type6TruckFlow); |
|||
// 1型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType1SpecialVehicleFlow(type1SpecialVehicleFlow); |
|||
// 2型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType2SpecialVehicleFlow(type2SpecialVehicleFlow); |
|||
// 3型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType3SpecialVehicleFlow(type3SpecialVehicleFlow); |
|||
// 4型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType4SpecialVehicleFlow(type4SpecialVehicleFlow); |
|||
// 5型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType5SpecialVehicleFlow(type5SpecialVehicleFlow); |
|||
// 6型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType6SpecialVehicleFlow(type6SpecialVehicleFlow); |
|||
|
|||
return dcTollStationStatisticsData; |
|||
|
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,234 @@ |
|||
package com.zc.business.service.impl; |
|||
|
|||
import cn.hutool.core.date.DateTime; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.ruoyi.common.annotation.DataSource; |
|||
import com.ruoyi.common.enums.DataSourceType; |
|||
import com.zc.business.domain.*; |
|||
import com.zc.business.domain.OdsTollEtctuData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.enums.VehicleTypeEnum; |
|||
import com.zc.business.mapper.OdsTollEtctuDataMapper; |
|||
import com.zc.business.service.IOdsTollEtctuDataService; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 门架流水数据 |
|||
*/ |
|||
@Service |
|||
@DataSource(value = DataSourceType.SLAVE)//切换数据源
|
|||
public class OdsTollEtctuDataImpl extends ServiceImpl<OdsTollEtctuDataMapper, OdsTollEtctuData> |
|||
implements IOdsTollEtctuDataService { |
|||
/** |
|||
* 获取最后一小时的门架流水数据列表。 |
|||
* |
|||
* @return List<OdsTollEtctuData> - 返回最后一小时的门架流水数据列表。如果没有数据,则返回空列表。 |
|||
*/ |
|||
@Override |
|||
public List<OdsTollEtctuData> lastHourData() { |
|||
// 创建查询条件包装器
|
|||
LambdaQueryWrapper<OdsTollEtctuData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
// 计算一小时前的时间点
|
|||
DateTime lastHour = DateUtil.offsetHour(new Date(), -1); |
|||
// 设置查询条件,查询时间包含在lastHour内的数据
|
|||
queryWrapper.between(OdsTollEtctuData::getTranstime, DateUtil.beginOfHour(lastHour), DateUtil.endOfHour(lastHour)); |
|||
// 根据查询条件获取数据列表并返回
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
/** |
|||
* 获取当月的门架流水数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含当月所有符合条件的门架流水数据对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollEtctuData> - 当月的门架流水数据列表。 |
|||
*/ |
|||
@Override |
|||
public List<OdsTollEtctuData> currentMonthData() { |
|||
// 创建查询条件包装器
|
|||
LambdaQueryWrapper<OdsTollEtctuData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
// 设置查询条件,查询当前月份的所有数据
|
|||
queryWrapper.between(OdsTollEtctuData::getTranstime, DateUtil.beginOfMonth(new Date()), new Date()); |
|||
// 根据查询条件获取数据列表并返回
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
/** |
|||
* 计算门架在指定时间段内的统计数据。 |
|||
* |
|||
* @param odsTollEtctuDataList 包含门架数据的列表,不应为null或空。 |
|||
* @return 返回一个包含各门架统计数据的列表。如果输入列表为空,则返回空列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcGantryStatisticsData> calculateGantryStatistics(List<OdsTollEtctuData> odsTollEtctuDataList) { |
|||
|
|||
// 检查输入列表是否为空,如果是则直接返回空列表
|
|||
if (odsTollEtctuDataList == null || odsTollEtctuDataList.isEmpty()) { |
|||
return new ArrayList<>(); |
|||
} |
|||
|
|||
// 使用Stream API按入口站号和入口时间进行分组
|
|||
Map<String, Map<String, List<OdsTollEtctuData>>> groupedData = |
|||
odsTollEtctuDataList.stream() |
|||
.collect(Collectors.groupingBy( |
|||
OdsTollEtctuData::getGantryid, // 按入口站号分组
|
|||
Collectors.groupingBy(odsTollEnpassData -> DateUtil.beginOfHour(odsTollEnpassData.getTranstime()).toString()) // 在每个入口站内按入口通行时间进一步分组
|
|||
)); |
|||
|
|||
// 遍历分组后的数据,计算每个门架每个时间周期内的统计数据
|
|||
List<DcGantryStatisticsData> dcGantryStatisticsDataList = new ArrayList<>(); |
|||
groupedData.forEach((gantryid, timeGroupedData) -> timeGroupedData.forEach((entime, dataList) -> dcGantryStatisticsDataList.add(trafficStatistics(dataList)))); |
|||
|
|||
return dcGantryStatisticsDataList; |
|||
} |
|||
|
|||
/** |
|||
* 计算交通统计数据 |
|||
* |
|||
* @param list 包含收费过境数据的列表 |
|||
* @return DcGantryStatisticsData 对象,包含计算后的交通统计数据 |
|||
*/ |
|||
private DcGantryStatisticsData trafficStatistics(List<OdsTollEtctuData> list) { |
|||
|
|||
// 创建DcGantryStatisticsData对象并初始化
|
|||
DcGantryStatisticsData dcGantryStatisticsData = new DcGantryStatisticsData(); |
|||
|
|||
// 初始化车流量总和
|
|||
int trafficVolume = 0; |
|||
|
|||
// 初始化1型客车车流量
|
|||
int type1PassengerFlow = 0; |
|||
// 初始化2型客车车流量
|
|||
int type2PassengerFlow = 0; |
|||
// 初始化3型客车车流量
|
|||
int type3PassengerFlow = 0; |
|||
// 初始化4型客车车流量
|
|||
int type4PassengerFlow = 0; |
|||
|
|||
// 初始化1型货车车流量
|
|||
int type1TruckFlow = 0; |
|||
// 初始化2型货车车流量
|
|||
int type2TruckFlow = 0; |
|||
// 初始化3型货车车流量
|
|||
int type3TruckFlow = 0; |
|||
// 初始化4型货车车流量
|
|||
int type4TruckFlow = 0; |
|||
// 初始化5型货车车流量
|
|||
int type5TruckFlow = 0; |
|||
// 初始化6型货车车流量
|
|||
int type6TruckFlow = 0; |
|||
|
|||
// 初始化1型专项作业车车流量
|
|||
int type1SpecialVehicleFlow = 0; |
|||
// 初始化2型专项作业车车流量
|
|||
int type2SpecialVehicleFlow = 0; |
|||
// 初始化3型专项作业车车流量
|
|||
int type3SpecialVehicleFlow = 0; |
|||
// 初始化4型专项作业车车流量
|
|||
int type4SpecialVehicleFlow = 0; |
|||
// 初始化5型专项作业车车流量
|
|||
int type5SpecialVehicleFlow = 0; |
|||
// 初始化6型专项作业车车流量
|
|||
int type6SpecialVehicleFlow = 0; |
|||
|
|||
for (OdsTollEtctuData odsTollEtctuData : list) { |
|||
Integer vehicletype = odsTollEtctuData.getVehicletype(); |
|||
|
|||
trafficVolume += 1; |
|||
|
|||
if (VehicleTypeEnum.TYPE_1_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type1PassengerFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_2_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type2PassengerFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_3_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type3PassengerFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_4_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type4PassengerFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_1_TRUCK.getValue().equals(vehicletype)) { |
|||
type1TruckFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_2_TRUCK.getValue().equals(vehicletype)) { |
|||
type2TruckFlow+= 1; |
|||
} else if (VehicleTypeEnum.TYPE_3_TRUCK.getValue().equals(vehicletype)) { |
|||
type3TruckFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_4_TRUCK.getValue().equals(vehicletype)) { |
|||
type4TruckFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_5_TRUCK.getValue().equals(vehicletype)) { |
|||
type5TruckFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_6_TRUCK.getValue().equals(vehicletype)) { |
|||
type6TruckFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_1_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type1SpecialVehicleFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_2_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type2SpecialVehicleFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_3_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type3SpecialVehicleFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_4_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type4SpecialVehicleFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_5_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type5SpecialVehicleFlow += 1; |
|||
} else if (VehicleTypeEnum.TYPE_6_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type6SpecialVehicleFlow += 1; |
|||
} |
|||
} |
|||
|
|||
// 使用第一个数据项的信息填充汇总统计对象的基本属性
|
|||
OdsTollEtctuData firstOdsTollEtctuData = list.iterator().next(); |
|||
|
|||
// 门架标识
|
|||
dcGantryStatisticsData.setGantryCode(firstOdsTollEtctuData.getGantryid()); |
|||
Date date = DateUtil.beginOfHour(firstOdsTollEtctuData.getTranstime()); |
|||
// 统计时间
|
|||
dcGantryStatisticsData.setStatisticalDate(date); |
|||
// 上报时间
|
|||
dcGantryStatisticsData.setReportTime(date); |
|||
// 统计粒度
|
|||
dcGantryStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.DAY); |
|||
|
|||
// 车流量
|
|||
dcGantryStatisticsData.setTrafficVolume(trafficVolume); |
|||
// 1型客车车流量
|
|||
dcGantryStatisticsData.setType1PassengerFlow(type1PassengerFlow); |
|||
// 2型客车车流量
|
|||
dcGantryStatisticsData.setType2PassengerFlow(type2PassengerFlow); |
|||
// 3型客车车流量
|
|||
dcGantryStatisticsData.setType3PassengerFlow(type3PassengerFlow); |
|||
// 4型客车车流量
|
|||
dcGantryStatisticsData.setType4PassengerFlow(type4PassengerFlow); |
|||
// 1型货车车流量
|
|||
dcGantryStatisticsData.setType1TruckFlow(type1TruckFlow); |
|||
// 2型货车车流量
|
|||
dcGantryStatisticsData.setType2TruckFlow(type2TruckFlow); |
|||
// 3型货车车流量
|
|||
dcGantryStatisticsData.setType3TruckFlow(type3TruckFlow); |
|||
// 4型货车车流量
|
|||
dcGantryStatisticsData.setType4TruckFlow(type4TruckFlow); |
|||
// 5型货车车流量
|
|||
dcGantryStatisticsData.setType5TruckFlow(type5TruckFlow); |
|||
// 6型货车车流量
|
|||
dcGantryStatisticsData.setType6TruckFlow(type6TruckFlow); |
|||
// 1型专项作业车车流量
|
|||
dcGantryStatisticsData.setType1SpecialVehicleFlow(type1SpecialVehicleFlow); |
|||
// 2型专项作业车车流量
|
|||
dcGantryStatisticsData.setType2SpecialVehicleFlow(type2SpecialVehicleFlow); |
|||
// 3型专项作业车车流量
|
|||
dcGantryStatisticsData.setType3SpecialVehicleFlow(type3SpecialVehicleFlow); |
|||
// 4型专项作业车车流量
|
|||
dcGantryStatisticsData.setType4SpecialVehicleFlow(type4SpecialVehicleFlow); |
|||
// 5型专项作业车车流量
|
|||
dcGantryStatisticsData.setType5SpecialVehicleFlow(type5SpecialVehicleFlow); |
|||
// 6型专项作业车车流量
|
|||
dcGantryStatisticsData.setType6SpecialVehicleFlow(type6SpecialVehicleFlow); |
|||
|
|||
return dcGantryStatisticsData; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,239 @@ |
|||
package com.zc.business.service.impl; |
|||
|
|||
import cn.hutool.core.date.DateTime; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.ruoyi.common.annotation.DataSource; |
|||
import com.ruoyi.common.enums.DataSourceType; |
|||
import com.zc.business.domain.*; |
|||
import com.zc.business.domain.OdsTollExpassData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.enums.VehicleTypeEnum; |
|||
import com.zc.business.mapper.OdsTollExpassDataMapper; |
|||
import com.zc.business.service.IOdsTollExpassDataService; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 收费站出口流水数据 |
|||
*/ |
|||
@Service |
|||
@DataSource(value = DataSourceType.SLAVE)//切换数据源
|
|||
public class OdsTollExpassDataServiceImpl extends ServiceImpl<OdsTollExpassDataMapper, OdsTollExpassData> |
|||
implements IOdsTollExpassDataService { |
|||
/** |
|||
* 获取过去一小时的OdsTollExpassData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含过去一小时所有符合条件的OdsTollExpassData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollExpassData> - 过去一小时的OdsTollExpassData数据列表。 |
|||
*/ |
|||
@Override |
|||
public List<OdsTollExpassData> lastHourData() { |
|||
// 创建查询条件包装器
|
|||
LambdaQueryWrapper<OdsTollExpassData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
// 计算一小时前的时间点
|
|||
DateTime lastHour = DateUtil.offsetHour(new Date(), -1); |
|||
// 设置查询条件,查询时间包含在lastHour内的数据
|
|||
queryWrapper.between(OdsTollExpassData::getExtime, DateUtil.beginOfHour(lastHour), DateUtil.endOfHour(lastHour)); |
|||
// 根据查询条件获取数据列表并返回
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
/** |
|||
* 获取当月的OdsTollExpassData数据列表。 |
|||
* |
|||
* <p>此方法不接受任何参数,返回一个包含当月所有符合条件的OdsTollExpassData对象的列表。 |
|||
* 该列表可用于进一步的数据分析和处理。 |
|||
* |
|||
* @return List<OdsTollExpassData> - 当月的OdsTollExpassData数据列表。 |
|||
*/ |
|||
@Override |
|||
public List<OdsTollExpassData> currentMonthData() { |
|||
// 创建查询条件包装器
|
|||
LambdaQueryWrapper<OdsTollExpassData> queryWrapper = new LambdaQueryWrapper<>(); |
|||
// 设置查询条件,查询当前月份的所有数据
|
|||
queryWrapper.between(OdsTollExpassData::getExtime, DateUtil.beginOfMonth(new Date()), new Date()); |
|||
// 根据查询条件获取数据列表并返回
|
|||
return list(queryWrapper); |
|||
} |
|||
|
|||
/** |
|||
* 计算收费站在指定时间段内的统计数据。 |
|||
* |
|||
* @param list 包含收费通行数据的列表,不应为null或空。 |
|||
* @return 返回一个包含各收费站统计数据的列表。如果输入列表为空,则返回空列表。 |
|||
*/ |
|||
@Override |
|||
public List<DcTollStationStatisticsData> calculateTollStationStatistics(List<OdsTollExpassData> list) { |
|||
// 检查输入列表是否为空,如果是则直接返回空列表
|
|||
if (list == null || list.isEmpty()) { |
|||
return new ArrayList<>(); |
|||
} |
|||
|
|||
// 使用Stream API按入口站号和入口时间进行分组
|
|||
Map<String, Map<String, List<OdsTollExpassData>>> groupedData = |
|||
list.stream() |
|||
.collect(Collectors.groupingBy( |
|||
OdsTollExpassData::getExtollstationid, // 按入口站号分组
|
|||
Collectors.groupingBy(odsTollExpassData -> DateUtil.beginOfHour(odsTollExpassData.getExtime()).toString()) // 在每个入口站内按入口通行时间进一步分组
|
|||
)); |
|||
|
|||
// 遍历分组后的数据,计算每个收费站每个时间周期内的统计数据
|
|||
List<DcTollStationStatisticsData> dcTollStationStatisticsDataList = new ArrayList<>(); |
|||
groupedData.forEach((extollstationid, timeGroupedData) -> timeGroupedData.forEach((entime, dataList) -> dcTollStationStatisticsDataList.add(trafficStatistics(dataList)))); |
|||
|
|||
return dcTollStationStatisticsDataList; |
|||
} |
|||
|
|||
/** |
|||
* 计算交通统计数据 |
|||
* |
|||
* @param list 包含收费过境数据的列表 |
|||
* @return DcTollStationStatisticsData 对象,包含计算后的交通统计数据 |
|||
*/ |
|||
private DcTollStationStatisticsData trafficStatistics(List<OdsTollExpassData> list) { |
|||
|
|||
// 创建DcTollStationStatisticsData对象并初始化
|
|||
DcTollStationStatisticsData dcTollStationStatisticsData = new DcTollStationStatisticsData(); |
|||
|
|||
// 初始化车流量总和
|
|||
int trafficVolume = 0; |
|||
|
|||
// 初始化1型客车车流量
|
|||
int type1PassengerFlow = 0; |
|||
// 初始化2型客车车流量
|
|||
int type2PassengerFlow = 0; |
|||
// 初始化3型客车车流量
|
|||
int type3PassengerFlow = 0; |
|||
// 初始化4型客车车流量
|
|||
int type4PassengerFlow = 0; |
|||
|
|||
// 初始化1型货车车流量
|
|||
int type1TruckFlow = 0; |
|||
// 初始化2型货车车流量
|
|||
int type2TruckFlow = 0; |
|||
// 初始化3型货车车流量
|
|||
int type3TruckFlow = 0; |
|||
// 初始化4型货车车流量
|
|||
int type4TruckFlow = 0; |
|||
// 初始化5型货车车流量
|
|||
int type5TruckFlow = 0; |
|||
// 初始化6型货车车流量
|
|||
int type6TruckFlow = 0; |
|||
|
|||
// 初始化1型专项作业车车流量
|
|||
int type1SpecialVehicleFlow = 0; |
|||
// 初始化2型专项作业车车流量
|
|||
int type2SpecialVehicleFlow = 0; |
|||
// 初始化3型专项作业车车流量
|
|||
int type3SpecialVehicleFlow = 0; |
|||
// 初始化4型专项作业车车流量
|
|||
int type4SpecialVehicleFlow = 0; |
|||
// 初始化5型专项作业车车流量
|
|||
int type5SpecialVehicleFlow = 0; |
|||
// 初始化6型专项作业车车流量
|
|||
int type6SpecialVehicleFlow = 0; |
|||
|
|||
for (OdsTollExpassData odsTollExpassData : list) { |
|||
Integer vcount = odsTollExpassData.getVcount(); |
|||
Integer vehicletype = odsTollExpassData.getExvehicletype(); |
|||
|
|||
trafficVolume += vcount; |
|||
|
|||
if (VehicleTypeEnum.TYPE_1_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type1PassengerFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_2_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type2PassengerFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_3_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type3PassengerFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_4_PASSENGER_CAR.getValue().equals(vehicletype)) { |
|||
type4PassengerFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_1_TRUCK.getValue().equals(vehicletype)) { |
|||
type1TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_2_TRUCK.getValue().equals(vehicletype)) { |
|||
type2TruckFlow+= vcount; |
|||
} else if (VehicleTypeEnum.TYPE_3_TRUCK.getValue().equals(vehicletype)) { |
|||
type3TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_4_TRUCK.getValue().equals(vehicletype)) { |
|||
type4TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_5_TRUCK.getValue().equals(vehicletype)) { |
|||
type5TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_6_TRUCK.getValue().equals(vehicletype)) { |
|||
type6TruckFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_1_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type1SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_2_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type2SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_3_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type3SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_4_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type4SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_5_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type5SpecialVehicleFlow += vcount; |
|||
} else if (VehicleTypeEnum.TYPE_6_SPECIAL_PURPOSE_VEHICLE.getValue().equals(vehicletype)) { |
|||
type6SpecialVehicleFlow += vcount; |
|||
} |
|||
} |
|||
|
|||
// 使用第一个数据项的信息填充汇总统计对象的基本属性
|
|||
OdsTollExpassData firstOdsTollEnpassData = list.iterator().next(); |
|||
|
|||
// 收费站站点标识
|
|||
dcTollStationStatisticsData.setTollStationCode(firstOdsTollEnpassData.getExtollstationid()); |
|||
Date date = DateUtil.beginOfHour(firstOdsTollEnpassData.getExtime()); |
|||
// 统计时间
|
|||
dcTollStationStatisticsData.setStatisticalDate(date); |
|||
// 上报时间
|
|||
dcTollStationStatisticsData.setReportTime(date); |
|||
// 统计粒度
|
|||
dcTollStationStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.DAY); |
|||
// 出入类型
|
|||
dcTollStationStatisticsData.setAccessType(DcTollStationStatisticsData.ENTRANCE); |
|||
|
|||
// 车流量
|
|||
dcTollStationStatisticsData.setTrafficVolume(trafficVolume); |
|||
// 1型客车车流量
|
|||
dcTollStationStatisticsData.setType1PassengerFlow(type1PassengerFlow); |
|||
// 2型客车车流量
|
|||
dcTollStationStatisticsData.setType2PassengerFlow(type2PassengerFlow); |
|||
// 3型客车车流量
|
|||
dcTollStationStatisticsData.setType3PassengerFlow(type3PassengerFlow); |
|||
// 4型客车车流量
|
|||
dcTollStationStatisticsData.setType4PassengerFlow(type4PassengerFlow); |
|||
// 1型货车车流量
|
|||
dcTollStationStatisticsData.setType1TruckFlow(type1TruckFlow); |
|||
// 2型货车车流量
|
|||
dcTollStationStatisticsData.setType2TruckFlow(type2TruckFlow); |
|||
// 3型货车车流量
|
|||
dcTollStationStatisticsData.setType3TruckFlow(type3TruckFlow); |
|||
// 4型货车车流量
|
|||
dcTollStationStatisticsData.setType4TruckFlow(type4TruckFlow); |
|||
// 5型货车车流量
|
|||
dcTollStationStatisticsData.setType5TruckFlow(type5TruckFlow); |
|||
// 6型货车车流量
|
|||
dcTollStationStatisticsData.setType6TruckFlow(type6TruckFlow); |
|||
// 1型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType1SpecialVehicleFlow(type1SpecialVehicleFlow); |
|||
// 2型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType2SpecialVehicleFlow(type2SpecialVehicleFlow); |
|||
// 3型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType3SpecialVehicleFlow(type3SpecialVehicleFlow); |
|||
// 4型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType4SpecialVehicleFlow(type4SpecialVehicleFlow); |
|||
// 5型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType5SpecialVehicleFlow(type5SpecialVehicleFlow); |
|||
// 6型专项作业车车流量
|
|||
dcTollStationStatisticsData.setType6SpecialVehicleFlow(type6SpecialVehicleFlow); |
|||
|
|||
return dcTollStationStatisticsData; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,18 @@ |
|||
package com.zc.business.service.impl; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.ruoyi.common.annotation.DataSource; |
|||
import com.ruoyi.common.enums.DataSourceType; |
|||
import com.zc.business.domain.OdsTollViuData; |
|||
import com.zc.business.mapper.OdsTollViuDataMapper; |
|||
import com.zc.business.service.IOdsTollViuDataService; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
/** |
|||
* 门架牌识流水数据 |
|||
*/ |
|||
@Service |
|||
@DataSource(value = DataSourceType.SLAVE)//切换数据源
|
|||
public class OdsTollViuDataServiceImpl extends ServiceImpl<OdsTollViuDataMapper, OdsTollViuData> |
|||
implements IOdsTollViuDataService { |
|||
} |
@ -0,0 +1,148 @@ |
|||
package com.zc.business.statistics.cache.gantry; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcGantryStatisticsData; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* |
|||
* 以天为单位的门架数据缓存类,用于存储和管理门架统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class DailyTrafficGantryStatisticsCache extends AbstractTrafficStatisticsCache<DcGantryStatisticsData> { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, DailyTrafficGantryStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = 26 * 60 * 60; // 缓存数据最长保留25小时
|
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 24 + 1 + 1000; // 缓存的最大条目数
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private DailyTrafficGantryStatisticsCache() { |
|||
} |
|||
|
|||
/** |
|||
* 添加门架数据到缓存中 |
|||
* |
|||
* @param dcGantryStatisticsData 待添加的门架数据 |
|||
*/ |
|||
public static void addCacheData(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 获取或新建对应的缓存实例
|
|||
DailyTrafficGantryStatisticsCache instance = getInstance(dcGantryStatisticsData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("门架数据缓存出现异常,最大缓存量达到设定上线 {}, 当前门架是 {}", MAX_CAPACITY, dcGantryStatisticsData.getGantryCode()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcGantryStatisticsData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcGantryStatisticsData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
// 更新上报时间
|
|||
dcGantryStatisticsData.setReportTime(dcGantryStatisticsData.getStatisticalDate()); |
|||
// 更新数据周期类型
|
|||
dcGantryStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.DAY); |
|||
// 更新统计日期
|
|||
dcGantryStatisticsData.setStatisticalDate(dcGantryStatisticsData.getStatisticalDate(), TrafficDataPeriodTypeEnum.DAY); |
|||
|
|||
// 移除旧数据
|
|||
instance.getData().remove(dcGantryStatisticsData); |
|||
// 添加数据
|
|||
instance.getData().add(dcGantryStatisticsData); |
|||
} |
|||
|
|||
/** |
|||
* 获取或创建对应设备与日期的DailyTrafficGantryStatisticsCache实例 |
|||
* |
|||
* @param dcGantryStatisticsData 门架数据统计定义 |
|||
* @return 对应的门架数据缓存实例 |
|||
*/ |
|||
private static DailyTrafficGantryStatisticsCache getInstance(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcGantryStatisticsData), k -> new DailyTrafficGantryStatisticsCache()); |
|||
} |
|||
|
|||
/** |
|||
* 生成缓存键。 |
|||
* <p>此方法通过组合门架编号、统计日期来生成一个唯一的缓存键。</p> |
|||
* |
|||
* @param dcGantryStatisticsData 门架统计数据对象,包含门架编号、统计日期 |
|||
* @return 缓存键,格式为"门架编号|格式化后的统计日期" |
|||
*/ |
|||
public static String generateCacheKey(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 获取门架标识
|
|||
String gantryCode = dcGantryStatisticsData.getGantryCode(); |
|||
|
|||
// 格式化统计日期
|
|||
String formattedDate = formatDate(dcGantryStatisticsData.getStatisticalDate()); |
|||
|
|||
// 组合门架编号、格式化后的统计日期作为缓存键
|
|||
return gantryCode + "|" + formattedDate; |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的门架数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(DailyTrafficGantryStatisticsCache::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,152 @@ |
|||
package com.zc.business.statistics.cache.gantry; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcGantryStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* |
|||
* 以月为单位的门架数据缓存类,用于存储和管理门架统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class MonthlyTrafficGantryStatisticsCache extends AbstractTrafficStatisticsCache<DcGantryStatisticsData> { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, MonthlyTrafficGantryStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = (60 * 60) * (31 * 24 + 2); |
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 31 + 1000; // 缓存的最大条目数
|
|||
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private MonthlyTrafficGantryStatisticsCache() { |
|||
} |
|||
|
|||
/** |
|||
* 添加门架数据到缓存中 |
|||
* |
|||
* @param dcGantryStatisticsData 待添加的门架数据 |
|||
*/ |
|||
public static void addCacheData(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 获取或新建对应的缓存实例
|
|||
MonthlyTrafficGantryStatisticsCache instance = getInstance(dcGantryStatisticsData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("门架数据缓存出现异常,最大缓存量达到设定上线 {}, 当前门架是 {}", MAX_CAPACITY, dcGantryStatisticsData.getGantryCode()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcGantryStatisticsData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcGantryStatisticsData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
// 更新上报时间
|
|||
dcGantryStatisticsData.setReportTime(dcGantryStatisticsData.getStatisticalDate()); |
|||
// 更新数据周期类型
|
|||
dcGantryStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.MONTH); |
|||
// 更新统计日期
|
|||
dcGantryStatisticsData.setStatisticalDate(dcGantryStatisticsData.getStatisticalDate(), TrafficDataPeriodTypeEnum.MONTH); |
|||
|
|||
// 移除旧数据
|
|||
instance.getData().remove(dcGantryStatisticsData); |
|||
// 添加数据
|
|||
instance.getData().add(dcGantryStatisticsData); |
|||
} |
|||
|
|||
/** |
|||
* 获取月门架信息缓存的实例。 |
|||
* <p> |
|||
* 根据传入的门架在一定周期(月)内的统计数据,计算并返回对应的缓存实例。 |
|||
* 如果缓存中已存在该实例,则直接返回;否则,创建新的缓存实例并加入缓存。 |
|||
* </p> |
|||
* |
|||
* @param dcGantryStatisticsData 门架统计数据,用于生成缓存键。 |
|||
* @return 缓存中的或新创建的月门架统计信息缓存实例。 |
|||
*/ |
|||
private static MonthlyTrafficGantryStatisticsCache getInstance(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcGantryStatisticsData), k -> new MonthlyTrafficGantryStatisticsCache()); |
|||
} |
|||
|
|||
/** |
|||
* 生成缓存键。 |
|||
* <p>此方法通过组合门架编号、统计日期和访问类型来生成一个唯一的缓存键。</p> |
|||
* |
|||
* @param dcGantryStatisticsData 门架统计数据对象,包含门架编号、统计日期 |
|||
* @return 缓存键,格式为"门架编号|格式化后的统计日期" |
|||
*/ |
|||
public static String generateCacheKey(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 获取门架标识
|
|||
String gantryCode = dcGantryStatisticsData.getGantryCode(); |
|||
|
|||
// 格式化统计日期
|
|||
String formattedDate = formatDate(dcGantryStatisticsData.getStatisticalDate()); |
|||
|
|||
// 组合门架编号、格式化后的统计日期和访问类型作为缓存键
|
|||
return gantryCode + "|" + formattedDate; |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(MonthlyTrafficGantryStatisticsCache::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,154 @@ |
|||
package com.zc.business.statistics.cache.gantry; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcGantryStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 以季度为单位的门架数据缓存类,用于存储和管理门架统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class QuarterlyTrafficGantryStatisticsCache extends AbstractTrafficStatisticsCache<DcGantryStatisticsData> { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, QuarterlyTrafficGantryStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = (60 * 60) * (3 * 31 * 24 + 2); |
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 3 + 1000; // 缓存的最大条目数
|
|||
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private QuarterlyTrafficGantryStatisticsCache() { |
|||
} |
|||
|
|||
/** |
|||
* 添加门架数据到缓存中 |
|||
* |
|||
* @param dcGantryStatisticsData 待添加的门架数据 |
|||
*/ |
|||
public static void addCacheData(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 获取或新建对应的缓存实例
|
|||
QuarterlyTrafficGantryStatisticsCache instance = getInstance(dcGantryStatisticsData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("门架数据缓存出现异常,最大缓存量达到设定上线 {}, 当前门架是 {}", MAX_CAPACITY, dcGantryStatisticsData.getGantryCode()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcGantryStatisticsData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcGantryStatisticsData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
// 更新上报时间
|
|||
dcGantryStatisticsData.setReportTime(dcGantryStatisticsData.getStatisticalDate()); |
|||
// 更新数据周期类型
|
|||
dcGantryStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.QUARTER); |
|||
// 更新统计日期
|
|||
dcGantryStatisticsData.setStatisticalDate(dcGantryStatisticsData.getStatisticalDate(), TrafficDataPeriodTypeEnum.QUARTER); |
|||
|
|||
// 移除旧数据
|
|||
instance.getData().remove(dcGantryStatisticsData); |
|||
// 添加数据
|
|||
instance.getData().add(dcGantryStatisticsData); |
|||
} |
|||
|
|||
/** |
|||
* 获取季度门架统计信息缓存的实例。 |
|||
* <p> |
|||
* 根据传入的门架在一定周期(季度)内的统计数据,计算并返回对应的缓存实例。 |
|||
* 如果缓存中已存在该实例,则直接返回;否则,创建新的缓存实例并加入缓存。 |
|||
* </p> |
|||
* |
|||
* @param dcGantryStatisticsData 门架统计数据,用于生成缓存键。 |
|||
* @return 缓存中的或新创建的季度门架统计信息缓存实例。 |
|||
*/ |
|||
private static QuarterlyTrafficGantryStatisticsCache getInstance(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 根据传入数据生成唯一键,并尝试从缓存中获取或创建新的缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcGantryStatisticsData), k -> new QuarterlyTrafficGantryStatisticsCache()); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 生成缓存键。 |
|||
* <p>此方法通过组合门架编号、统计日期和访问类型来生成一个唯一的缓存键。</p> |
|||
* |
|||
* @param dcGantryStatisticsData 门架统计数据对象,包含门架编号、统计日期和访问类型 |
|||
* @return 缓存键,格式为"门架编号|格式化后的统计日期|访问类型" |
|||
*/ |
|||
public static String generateCacheKey(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 获取门架标识
|
|||
String gantryCode = dcGantryStatisticsData.getGantryCode(); |
|||
|
|||
// 格式化统计日期
|
|||
String formattedDate = formatDate(dcGantryStatisticsData.getStatisticalDate()); |
|||
|
|||
// 组合门架编号、格式化后的统计日期缓存键
|
|||
return gantryCode + "|" + formattedDate; |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(QuarterlyTrafficGantryStatisticsCache::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,148 @@ |
|||
package com.zc.business.statistics.cache.gantry; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcGantryStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 以年为单位的门架数据缓存类,用于存储和管理门架统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class YearlyTrafficGantryStatisticsCache extends AbstractTrafficStatisticsCache<DcGantryStatisticsData> { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, YearlyTrafficGantryStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = (60 * 60) * (366 * 24 + 2); |
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 4 + 1000; // 缓存的最大条目数
|
|||
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private YearlyTrafficGantryStatisticsCache() { |
|||
} |
|||
|
|||
/** |
|||
* 添加门架数据到缓存中 |
|||
* |
|||
* @param dcGantryStatisticsData 待添加的门架数据 |
|||
*/ |
|||
public static void addCacheData(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 获取或新建对应的缓存实例
|
|||
YearlyTrafficGantryStatisticsCache instance = getInstance(dcGantryStatisticsData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("门架数据缓存出现异常,最大缓存量达到设定上线 {}, 当前门架是 {}", MAX_CAPACITY, dcGantryStatisticsData.getGantryCode()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcGantryStatisticsData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcGantryStatisticsData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
// 更新上报时间
|
|||
dcGantryStatisticsData.setReportTime(dcGantryStatisticsData.getStatisticalDate()); |
|||
// 更新数据周期类型
|
|||
dcGantryStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.YEAR); |
|||
// 更新统计日期
|
|||
dcGantryStatisticsData.setStatisticalDate(dcGantryStatisticsData.getStatisticalDate(), TrafficDataPeriodTypeEnum.YEAR); |
|||
|
|||
// 移除旧数据
|
|||
instance.getData().remove(dcGantryStatisticsData); |
|||
// 添加数据
|
|||
instance.getData().add(dcGantryStatisticsData); |
|||
} |
|||
|
|||
/** |
|||
* 获取或创建对应设备与日期的YearlyTrafficSectionStatisticsCache实例 |
|||
* |
|||
* @param DcGantryStatisticsData 交通断面数据统计定义 |
|||
* @return 对应的交通断面数据缓存实例 |
|||
*/ |
|||
private static YearlyTrafficGantryStatisticsCache getInstance(DcGantryStatisticsData DcGantryStatisticsData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(DcGantryStatisticsData), k -> new YearlyTrafficGantryStatisticsCache()); |
|||
} |
|||
|
|||
/** |
|||
* 生成缓存键。 |
|||
* <p>此方法通过组合门架编号、统计日期来生成一个唯一的缓存键。</p> |
|||
* |
|||
* @param dcGantryStatisticsData 门架统计数据对象,包含门架编号、统计日期 |
|||
* @return 缓存键,格式为"门架编号|格式化后的统计日期" |
|||
*/ |
|||
public static String generateCacheKey(DcGantryStatisticsData dcGantryStatisticsData) { |
|||
// 获取门架站点标识
|
|||
String gantryCode = dcGantryStatisticsData.getGantryCode(); |
|||
|
|||
// 格式化统计日期
|
|||
String formattedDate = formatDate(dcGantryStatisticsData.getStatisticalDate()); |
|||
|
|||
// 组合门架编号、格式化后的统计日期作为缓存键
|
|||
return gantryCode + "|" + formattedDate; |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(YearlyTrafficGantryStatisticsCache::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,148 @@ |
|||
package com.zc.business.statistics.cache.tollstation; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* |
|||
* 以天为单位的交通收费站站点数据缓存类,用于存储和管理收费站站点统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class DailyTrafficTollStationStatisticsCache extends AbstractTrafficStatisticsCache<DcTollStationStatisticsData> { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, DailyTrafficTollStationStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = 26 * 60 * 60; // 缓存数据最长保留25小时
|
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 24 + 1 + 1000; // 缓存的最大条目数
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private DailyTrafficTollStationStatisticsCache() { |
|||
} |
|||
|
|||
/** |
|||
* 添加收费站站点数据到缓存中 |
|||
* |
|||
* @param dcTollStationStatisticsData 待添加的收费站站点数据 |
|||
*/ |
|||
public static void addCacheData(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 获取或新建对应的缓存实例
|
|||
DailyTrafficTollStationStatisticsCache instance = getInstance(dcTollStationStatisticsData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("收费站站点数据缓存出现异常,最大缓存量达到设定上线 {}, 当前收费站点是 {}", MAX_CAPACITY, dcTollStationStatisticsData.getTollStationCode()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcTollStationStatisticsData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcTollStationStatisticsData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
// 更新上报时间
|
|||
dcTollStationStatisticsData.setReportTime(dcTollStationStatisticsData.getStatisticalDate()); |
|||
// 更新数据周期类型
|
|||
dcTollStationStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.DAY); |
|||
// 更新统计日期
|
|||
dcTollStationStatisticsData.setStatisticalDate(dcTollStationStatisticsData.getStatisticalDate(), TrafficDataPeriodTypeEnum.DAY); |
|||
|
|||
// 移除旧数据
|
|||
instance.getData().remove(dcTollStationStatisticsData); |
|||
// 添加数据
|
|||
instance.getData().add(dcTollStationStatisticsData); |
|||
} |
|||
|
|||
/** |
|||
* 获取或创建对应设备与日期的DailyTrafficTollStationStatisticsCache实例 |
|||
* |
|||
* @param dcTollStationStatisticsData 收费站站点数据统计定义 |
|||
* @return 对应的收费站站点数据缓存实例 |
|||
*/ |
|||
private static DailyTrafficTollStationStatisticsCache getInstance(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcTollStationStatisticsData), k -> new DailyTrafficTollStationStatisticsCache()); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 生成缓存键。 |
|||
* <p>此方法通过组合收费站编号、统计日期和访问类型来生成一个唯一的缓存键。</p> |
|||
* |
|||
* @param dcTollStationStatisticsData 收费站统计数据对象,包含收费站编号、统计日期和访问类型 |
|||
* @return 缓存键,格式为"收费站编号|格式化后的统计日期|访问类型" |
|||
*/ |
|||
public static String generateCacheKey(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 获取收费站站点标识
|
|||
String tollStationCode = dcTollStationStatisticsData.getTollStationCode(); |
|||
|
|||
// 格式化统计日期
|
|||
String formattedDate = formatDate(dcTollStationStatisticsData.getStatisticalDate()); |
|||
|
|||
// 组合收费站编号、格式化后的统计日期和访问类型作为缓存键
|
|||
return tollStationCode + "|" + formattedDate + "|" + dcTollStationStatisticsData.getAccessType(); |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的收费站站点数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(DailyTrafficTollStationStatisticsCache::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,152 @@ |
|||
package com.zc.business.statistics.cache.tollstation; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* |
|||
* 以月为单位的交通收费站站点数据缓存类,用于存储和管理收费站站点统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class MonthlyTrafficTollStationStatisticsCache extends AbstractTrafficStatisticsCache<DcTollStationStatisticsData> { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, MonthlyTrafficTollStationStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = (60 * 60) * (31 * 24 + 2); |
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 31 + 1000; // 缓存的最大条目数
|
|||
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private MonthlyTrafficTollStationStatisticsCache() { |
|||
} |
|||
|
|||
/** |
|||
* 添加收费站站点数据到缓存中 |
|||
* |
|||
* @param dcTollStationStatisticsData 待添加的收费站站点数据 |
|||
*/ |
|||
public static void addCacheData(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 获取或新建对应的缓存实例
|
|||
MonthlyTrafficTollStationStatisticsCache instance = getInstance(dcTollStationStatisticsData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("收费站站点数据缓存出现异常,最大缓存量达到设定上线 {}, 当前收费站点是 {}", MAX_CAPACITY, dcTollStationStatisticsData.getTollStationCode()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcTollStationStatisticsData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcTollStationStatisticsData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
// 更新上报时间
|
|||
dcTollStationStatisticsData.setReportTime(dcTollStationStatisticsData.getStatisticalDate()); |
|||
// 更新数据周期类型
|
|||
dcTollStationStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.MONTH); |
|||
// 更新统计日期
|
|||
dcTollStationStatisticsData.setStatisticalDate(dcTollStationStatisticsData.getStatisticalDate(), TrafficDataPeriodTypeEnum.MONTH); |
|||
|
|||
// 移除旧数据
|
|||
instance.getData().remove(dcTollStationStatisticsData); |
|||
// 添加数据
|
|||
instance.getData().add(dcTollStationStatisticsData); |
|||
} |
|||
|
|||
/** |
|||
* 获取月交通收费站统计信息缓存的实例。 |
|||
* <p> |
|||
* 根据传入的收费站在一定周期(月)内的统计数据,计算并返回对应的缓存实例。 |
|||
* 如果缓存中已存在该实例,则直接返回;否则,创建新的缓存实例并加入缓存。 |
|||
* </p> |
|||
* |
|||
* @param dcTollStationStatisticsData 收费站统计数据,用于生成缓存键。 |
|||
* @return 缓存中的或新创建的月交通收费站统计信息缓存实例。 |
|||
*/ |
|||
private static MonthlyTrafficTollStationStatisticsCache getInstance(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcTollStationStatisticsData), k -> new MonthlyTrafficTollStationStatisticsCache()); |
|||
} |
|||
|
|||
/** |
|||
* 生成缓存键。 |
|||
* <p>此方法通过组合收费站编号、统计日期和访问类型来生成一个唯一的缓存键。</p> |
|||
* |
|||
* @param dcTollStationStatisticsData 收费站统计数据对象,包含收费站编号、统计日期和访问类型 |
|||
* @return 缓存键,格式为"收费站编号|格式化后的统计日期|访问类型" |
|||
*/ |
|||
public static String generateCacheKey(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 获取收费站站点标识
|
|||
String tollStationCode = dcTollStationStatisticsData.getTollStationCode(); |
|||
|
|||
// 格式化统计日期
|
|||
String formattedDate = formatDate(dcTollStationStatisticsData.getStatisticalDate()); |
|||
|
|||
// 组合收费站编号、格式化后的统计日期和访问类型作为缓存键
|
|||
return tollStationCode + "|" + formattedDate + "|" + dcTollStationStatisticsData.getAccessType(); |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(MonthlyTrafficTollStationStatisticsCache::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,154 @@ |
|||
package com.zc.business.statistics.cache.tollstation; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 以季度为单位的交通收费站站点数据缓存类,用于存储和管理收费站站点统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class QuarterlyTrafficTollStationStatisticsCache extends AbstractTrafficStatisticsCache<DcTollStationStatisticsData> { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, QuarterlyTrafficTollStationStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = (60 * 60) * (3 * 31 * 24 + 2); |
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 3 + 1000; // 缓存的最大条目数
|
|||
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private QuarterlyTrafficTollStationStatisticsCache() { |
|||
} |
|||
|
|||
/** |
|||
* 添加收费站站点数据到缓存中 |
|||
* |
|||
* @param dcTollStationStatisticsData 待添加的收费站站点数据 |
|||
*/ |
|||
public static void addCacheData(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 获取或新建对应的缓存实例
|
|||
QuarterlyTrafficTollStationStatisticsCache instance = getInstance(dcTollStationStatisticsData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("收费站站点数据缓存出现异常,最大缓存量达到设定上线 {}, 当前收费站点是 {}", MAX_CAPACITY, dcTollStationStatisticsData.getTollStationCode()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcTollStationStatisticsData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcTollStationStatisticsData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
// 更新上报时间
|
|||
dcTollStationStatisticsData.setReportTime(dcTollStationStatisticsData.getStatisticalDate()); |
|||
// 更新数据周期类型
|
|||
dcTollStationStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.QUARTER); |
|||
// 更新统计日期
|
|||
dcTollStationStatisticsData.setStatisticalDate(dcTollStationStatisticsData.getStatisticalDate(), TrafficDataPeriodTypeEnum.QUARTER); |
|||
|
|||
// 移除旧数据
|
|||
instance.getData().remove(dcTollStationStatisticsData); |
|||
// 添加数据
|
|||
instance.getData().add(dcTollStationStatisticsData); |
|||
} |
|||
|
|||
/** |
|||
* 获取季度交通收费站统计信息缓存的实例。 |
|||
* <p> |
|||
* 根据传入的收费站在一定周期(季度)内的统计数据,计算并返回对应的缓存实例。 |
|||
* 如果缓存中已存在该实例,则直接返回;否则,创建新的缓存实例并加入缓存。 |
|||
* </p> |
|||
* |
|||
* @param dcTollStationStatisticsData 收费站统计数据,用于生成缓存键。 |
|||
* @return 缓存中的或新创建的季度交通收费站统计信息缓存实例。 |
|||
*/ |
|||
private static QuarterlyTrafficTollStationStatisticsCache getInstance(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 根据传入数据生成唯一键,并尝试从缓存中获取或创建新的缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(dcTollStationStatisticsData), k -> new QuarterlyTrafficTollStationStatisticsCache()); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 生成缓存键。 |
|||
* <p>此方法通过组合收费站编号、统计日期和访问类型来生成一个唯一的缓存键。</p> |
|||
* |
|||
* @param dcTollStationStatisticsData 收费站统计数据对象,包含收费站编号、统计日期和访问类型 |
|||
* @return 缓存键,格式为"收费站编号|格式化后的统计日期|访问类型" |
|||
*/ |
|||
public static String generateCacheKey(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 获取收费站站点标识
|
|||
String tollStationCode = dcTollStationStatisticsData.getTollStationCode(); |
|||
|
|||
// 格式化统计日期
|
|||
String formattedDate = formatDate(dcTollStationStatisticsData.getStatisticalDate()); |
|||
|
|||
// 组合收费站编号、格式化后的统计日期和访问类型作为缓存键
|
|||
return tollStationCode + "|" + formattedDate + "|" + dcTollStationStatisticsData.getAccessType(); |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(QuarterlyTrafficTollStationStatisticsCache::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,148 @@ |
|||
package com.zc.business.statistics.cache.tollstation; |
|||
|
|||
import cn.hutool.core.date.DateUnit; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 以年为单位的交通收费站站点数据缓存类,用于存储和管理收费站站点统计数据,同时提供了数据缓存的有效性管理和清理功能。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class YearlyTrafficTollStationStatisticsCache extends AbstractTrafficStatisticsCache<DcTollStationStatisticsData> { |
|||
|
|||
// 静态缓存容器,使用ConcurrentHashMap保证线程安全
|
|||
@Getter |
|||
private static final Map<String, YearlyTrafficTollStationStatisticsCache> cache = new ConcurrentHashMap<>(); |
|||
|
|||
// 最大缓存时间(单位:秒)
|
|||
private static final long MAX_CACHE_TIME = (60 * 60) * (366 * 24 + 2); |
|||
|
|||
// 最大容量限制,防止内存溢出
|
|||
private static final int MAX_CAPACITY = 4 + 1000; // 缓存的最大条目数
|
|||
|
|||
|
|||
// 私有构造函数,确保只能通过静态方法获取实例
|
|||
private YearlyTrafficTollStationStatisticsCache() { |
|||
} |
|||
|
|||
/** |
|||
* 添加收费站站点数据到缓存中 |
|||
* |
|||
* @param dcTollStationStatisticsData 待添加的收费站站点数据 |
|||
*/ |
|||
public static void addCacheData(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 获取或新建对应的缓存实例
|
|||
YearlyTrafficTollStationStatisticsCache instance = getInstance(dcTollStationStatisticsData); |
|||
|
|||
// 检查缓存容量是否达到上限
|
|||
if (instance.getData().size() >= MAX_CAPACITY) { |
|||
instance.getLogger().error("收费站站点数据缓存出现异常,最大缓存量达到设定上线 {}, 当前收费站点是 {}", MAX_CAPACITY, dcTollStationStatisticsData.getTollStationCode()); |
|||
return; |
|||
} |
|||
|
|||
// 更新最后添加时间
|
|||
instance.setLastAddedTime(DateUtil.date()); |
|||
|
|||
// 更新状态
|
|||
instance.setStored(false); |
|||
String formattedDate = formatDate(dcTollStationStatisticsData.getStatisticalDate()); |
|||
String key = generateCacheKey(dcTollStationStatisticsData); |
|||
|
|||
// 设置key和thatDay属性(仅在首次添加时)
|
|||
if (instance.getCacheKey() == null) { |
|||
instance.setCacheKey(key); |
|||
instance.setStatisticalDateStr(formattedDate); |
|||
} |
|||
|
|||
// 更新上报时间
|
|||
dcTollStationStatisticsData.setReportTime(dcTollStationStatisticsData.getStatisticalDate()); |
|||
// 更新数据周期类型
|
|||
dcTollStationStatisticsData.setPeriodType(TrafficDataPeriodTypeEnum.YEAR); |
|||
// 更新统计日期
|
|||
dcTollStationStatisticsData.setStatisticalDate(dcTollStationStatisticsData.getStatisticalDate(), TrafficDataPeriodTypeEnum.YEAR); |
|||
|
|||
// 移除旧数据
|
|||
instance.getData().remove(dcTollStationStatisticsData); |
|||
// 添加数据
|
|||
instance.getData().add(dcTollStationStatisticsData); |
|||
} |
|||
|
|||
/** |
|||
* 获取或创建对应设备与日期的YearlyTrafficSectionStatisticsCache实例 |
|||
* |
|||
* @param DcTollStationStatisticsData 交通断面数据统计定义 |
|||
* @return 对应的交通断面数据缓存实例 |
|||
*/ |
|||
private static YearlyTrafficTollStationStatisticsCache getInstance(DcTollStationStatisticsData DcTollStationStatisticsData) { |
|||
// 使用toKey方法生成唯一键,并根据此键计算并返回缓存实例
|
|||
return cache.computeIfAbsent(generateCacheKey(DcTollStationStatisticsData), k -> new YearlyTrafficTollStationStatisticsCache()); |
|||
} |
|||
|
|||
/** |
|||
* 生成缓存键。 |
|||
* <p>此方法通过组合收费站编号、统计日期和访问类型来生成一个唯一的缓存键。</p> |
|||
* |
|||
* @param dcTollStationStatisticsData 收费站统计数据对象,包含收费站编号、统计日期和访问类型 |
|||
* @return 缓存键,格式为"收费站编号|格式化后的统计日期|访问类型" |
|||
*/ |
|||
public static String generateCacheKey(DcTollStationStatisticsData dcTollStationStatisticsData) { |
|||
// 获取收费站站点标识
|
|||
String tollStationCode = dcTollStationStatisticsData.getTollStationCode(); |
|||
|
|||
// 格式化统计日期
|
|||
String formattedDate = formatDate(dcTollStationStatisticsData.getStatisticalDate()); |
|||
|
|||
// 组合收费站编号、格式化后的统计日期和访问类型作为缓存键
|
|||
return tollStationCode + "|" + formattedDate + "|" + dcTollStationStatisticsData.getAccessType(); |
|||
} |
|||
|
|||
/** |
|||
* 清除所有过期的交通断面数据缓存项 |
|||
*/ |
|||
public static void clearExpiredData() { |
|||
// 使用stream API找出所有过期的数据缓存项键
|
|||
Set<String> keysToRemove = cache.keySet().stream() |
|||
.filter(YearlyTrafficTollStationStatisticsCache::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,241 @@ |
|||
package com.zc.business.statistics.handler; |
|||
|
|||
import com.zc.business.domain.DcGantryStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.mapper.DcGantryStatisticsDataMapper; |
|||
import com.zc.business.service.IDcGantryStatisticsDataService; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import com.zc.business.statistics.cache.gantry.DailyTrafficGantryStatisticsCache; |
|||
import com.zc.business.statistics.cache.gantry.MonthlyTrafficGantryStatisticsCache; |
|||
import com.zc.business.statistics.cache.gantry.QuarterlyTrafficGantryStatisticsCache; |
|||
import com.zc.business.statistics.cache.gantry.YearlyTrafficGantryStatisticsCache; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.util.CollectionUtils; |
|||
|
|||
import javax.annotation.Resource; |
|||
import java.util.Collection; |
|||
import java.util.Map; |
|||
import java.util.function.Consumer; |
|||
|
|||
/** |
|||
* TrafficGantryStatistics类用于处理门架的统计数据。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Component |
|||
public class TrafficGantryStatistics { |
|||
|
|||
// 日志记录器
|
|||
protected final Logger logger = LoggerFactory.getLogger(this.getClass()); |
|||
|
|||
@Resource |
|||
private IDcGantryStatisticsDataService dcGantryStatisticsDataService; |
|||
|
|||
@Resource |
|||
private DcGantryStatisticsDataMapper dcGantryStatisticsDataMapper; |
|||
|
|||
|
|||
/** |
|||
* 定义每小时第20分钟执行的任务,用于清除过期缓存数据并将缓存中的数据整合后保存至数据库。 |
|||
*/ |
|||
@Scheduled(cron = "0 20 * * * ?") // 每小时的20分整点执行该任务
|
|||
public void performHourlyCleanupAndPersist() { |
|||
|
|||
// 添加日门架数据到缓存中
|
|||
dcGantryStatisticsDataService.lastHourData().forEach(DailyTrafficGantryStatisticsCache::addCacheData); |
|||
|
|||
// 清除已过期的缓存数据
|
|||
DailyTrafficGantryStatisticsCache.clearExpiredData(); |
|||
MonthlyTrafficGantryStatisticsCache.clearExpiredData(); |
|||
QuarterlyTrafficGantryStatisticsCache.clearExpiredData(); |
|||
YearlyTrafficGantryStatisticsCache.clearExpiredData(); |
|||
|
|||
// 整合缓存数据并保存至数据库
|
|||
// 将缓存中的数据按日统计后保存至数据库
|
|||
// 添加月门架数据到缓存中
|
|||
persistAggregatedData(DailyTrafficGantryStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.DAY, MonthlyTrafficGantryStatisticsCache::addCacheData); |
|||
// 将缓存中的数据按月统计后保存至数据库
|
|||
// 添加季度门架数据到缓存中
|
|||
persistAggregatedData(MonthlyTrafficGantryStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.MONTH, QuarterlyTrafficGantryStatisticsCache::addCacheData); |
|||
// 将缓存中的数据按季度统计后保存至数据库
|
|||
// 添加年门架数据到缓存中
|
|||
persistAggregatedData(QuarterlyTrafficGantryStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.QUARTER, YearlyTrafficGantryStatisticsCache::addCacheData); |
|||
// 将缓存中的数据按年统计后保存至数据库
|
|||
persistAggregatedData(YearlyTrafficGantryStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.YEAR, (a) -> {}); |
|||
} |
|||
|
|||
/** |
|||
* 将缓存中的数据统计后保存至数据库。 |
|||
*/ |
|||
public void persistAggregatedData( |
|||
Map<String, ? extends AbstractTrafficStatisticsCache<DcGantryStatisticsData>> cache, |
|||
TrafficDataPeriodTypeEnum periodType, |
|||
Consumer<DcGantryStatisticsData> consumer |
|||
) { |
|||
for (AbstractTrafficStatisticsCache<DcGantryStatisticsData> data : cache.values()) { |
|||
// 如果数据已经存储过,则跳过此次处理
|
|||
if (data.isStored()) { |
|||
continue; |
|||
} |
|||
DcGantryStatisticsData aggregatedData = trafficStatistics(data.getData(), periodType); |
|||
if (dcGantryStatisticsDataMapper.insertOrUpdate(aggregatedData)) { |
|||
// 设置数据已存储状态
|
|||
data.setStored(true); |
|||
// 调用回调函数
|
|||
consumer.accept(aggregatedData); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 对给定的门架统计数据集合进行汇总处理。 |
|||
* |
|||
* @param dataCollection 门架统计数据的集合,不可为null或空。 |
|||
* @param trafficDataPeriodType 统计数据的时段类型,例如:小时、日、月等。 |
|||
* @return 汇总后的门架统计数据对象,如果输入数据为空则返回null。 |
|||
*/ |
|||
public DcGantryStatisticsData trafficStatistics(Collection<DcGantryStatisticsData> dataCollection, TrafficDataPeriodTypeEnum trafficDataPeriodType) { |
|||
|
|||
// 判断输入数据是否为空
|
|||
if (CollectionUtils.isEmpty(dataCollection)) { |
|||
return null; |
|||
} |
|||
|
|||
// 创建一个汇总统计用的对象
|
|||
DcGantryStatisticsData aggregatedData = new DcGantryStatisticsData(); |
|||
|
|||
// 初始化车流量总和
|
|||
int trafficVolume = 0; |
|||
|
|||
// 初始化1型客车车流量
|
|||
int type1PassengerFlow = 0; |
|||
// 初始化2型客车车流量
|
|||
int type2PassengerFlow = 0; |
|||
// 初始化3型客车车流量
|
|||
int type3PassengerFlow = 0; |
|||
// 初始化4型客车车流量
|
|||
int type4PassengerFlow = 0; |
|||
|
|||
// 初始化1型货车车流量
|
|||
int type1TruckFlow = 0; |
|||
// 初始化2型货车车流量
|
|||
int type2TruckFlow = 0; |
|||
// 初始化3型货车车流量
|
|||
int type3TruckFlow = 0; |
|||
// 初始化4型货车车流量
|
|||
int type4TruckFlow = 0; |
|||
// 初始化5型货车车流量
|
|||
int type5TruckFlow = 0; |
|||
// 初始化6型货车车流量
|
|||
int type6TruckFlow = 0; |
|||
|
|||
// 初始化1型专项作业车车流量
|
|||
int type1SpecialVehicleFlow = 0; |
|||
// 初始化2型专项作业车车流量
|
|||
int type2SpecialVehicleFlow = 0; |
|||
// 初始化3型专项作业车车流量
|
|||
int type3SpecialVehicleFlow = 0; |
|||
// 初始化4型专项作业车车流量
|
|||
int type4SpecialVehicleFlow = 0; |
|||
// 初始化5型专项作业车车流量
|
|||
int type5SpecialVehicleFlow = 0; |
|||
// 初始化6型专项作业车车流量
|
|||
int type6SpecialVehicleFlow = 0; |
|||
|
|||
|
|||
// 遍历数据集合,累加各类车辆的车流量
|
|||
for (DcGantryStatisticsData data: dataCollection) { |
|||
// 累加车流量
|
|||
trafficVolume += data.getTrafficVolume(); |
|||
// 累加1型客车车流量
|
|||
type1PassengerFlow += data.getType1PassengerFlow(); |
|||
// 累加2型客车车流量
|
|||
type2PassengerFlow += data.getType2PassengerFlow(); |
|||
// 累加3型客车车流量
|
|||
type3PassengerFlow += data.getType3PassengerFlow(); |
|||
// 累加4型客车车流量
|
|||
type4PassengerFlow += data.getType4PassengerFlow(); |
|||
|
|||
// 累加1型货车车流量
|
|||
type1TruckFlow += data.getType1TruckFlow(); |
|||
// 累加2型货车车流量
|
|||
type2TruckFlow += data.getType2TruckFlow(); |
|||
// 累加3型货车车流量
|
|||
type3TruckFlow += data.getType3TruckFlow(); |
|||
// 累加4型货车车流量
|
|||
type4TruckFlow += data.getType4TruckFlow(); |
|||
// 累加5型货车车流量
|
|||
type5TruckFlow += data.getType5TruckFlow(); |
|||
// 累加6型货车车流量
|
|||
type6TruckFlow += data.getType6TruckFlow(); |
|||
|
|||
// 累加1型专项作业车车流量
|
|||
type1SpecialVehicleFlow += data.getType1SpecialVehicleFlow(); |
|||
// 累加2型专项作业车车流量
|
|||
type2SpecialVehicleFlow += data.getType2SpecialVehicleFlow(); |
|||
// 累加3型专项作业车车流量
|
|||
type3SpecialVehicleFlow += data.getType3SpecialVehicleFlow(); |
|||
// 累加4型专项作业车车流量
|
|||
type4SpecialVehicleFlow += data.getType4SpecialVehicleFlow(); |
|||
// 累加5型专项作业车车流量
|
|||
type5SpecialVehicleFlow += data.getType5SpecialVehicleFlow(); |
|||
// 累加6型专项作业车车流量
|
|||
type6SpecialVehicleFlow += data.getType6SpecialVehicleFlow(); |
|||
} |
|||
|
|||
// 使用第一个数据项的信息填充汇总统计对象的基本属性
|
|||
DcGantryStatisticsData firstDcTrafficSectionData = dataCollection.iterator().next(); |
|||
|
|||
// 设置门架标识
|
|||
aggregatedData.setGantryCode(firstDcTrafficSectionData.getGantryCode()); |
|||
// 设置统计时间
|
|||
aggregatedData.setStatisticalDate(firstDcTrafficSectionData.getStatisticalDate(), trafficDataPeriodType); |
|||
// 上报时间
|
|||
aggregatedData.setReportTime(firstDcTrafficSectionData.getReportTime()); |
|||
// 时段类型
|
|||
aggregatedData.setPeriodType(trafficDataPeriodType); |
|||
|
|||
// 车流量
|
|||
aggregatedData.setTrafficVolume(trafficVolume); |
|||
// 1型客车车流量
|
|||
aggregatedData.setType1PassengerFlow(type1PassengerFlow); |
|||
// 2型客车车流量
|
|||
aggregatedData.setType2PassengerFlow(type2PassengerFlow); |
|||
// 3型客车车流量
|
|||
aggregatedData.setType3PassengerFlow(type3PassengerFlow); |
|||
// 4型客车车流量
|
|||
aggregatedData.setType4PassengerFlow(type4PassengerFlow); |
|||
// 1型货车车流量
|
|||
aggregatedData.setType1TruckFlow(type1TruckFlow); |
|||
// 2型货车车流量
|
|||
aggregatedData.setType2TruckFlow(type2TruckFlow); |
|||
// 3型货车车流量
|
|||
aggregatedData.setType3TruckFlow(type3TruckFlow); |
|||
// 4型货车车流量
|
|||
aggregatedData.setType4TruckFlow(type4TruckFlow); |
|||
// 5型货车车流量
|
|||
aggregatedData.setType5TruckFlow(type5TruckFlow); |
|||
// 6型货车车流量
|
|||
aggregatedData.setType6TruckFlow(type6TruckFlow); |
|||
// 1型专项作业车车流量
|
|||
aggregatedData.setType1SpecialVehicleFlow(type1SpecialVehicleFlow); |
|||
// 2型专项作业车车流量
|
|||
aggregatedData.setType2SpecialVehicleFlow(type2SpecialVehicleFlow); |
|||
// 3型专项作业车车流量
|
|||
aggregatedData.setType3SpecialVehicleFlow(type3SpecialVehicleFlow); |
|||
// 4型专项作业车车流量
|
|||
aggregatedData.setType4SpecialVehicleFlow(type4SpecialVehicleFlow); |
|||
// 5型专项作业车车流量
|
|||
aggregatedData.setType5SpecialVehicleFlow(type5SpecialVehicleFlow); |
|||
// 6型专项作业车车流量
|
|||
aggregatedData.setType6SpecialVehicleFlow(type6SpecialVehicleFlow); |
|||
|
|||
// 生成主键
|
|||
aggregatedData.generateUniqueId(); |
|||
|
|||
return aggregatedData; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,243 @@ |
|||
package com.zc.business.statistics.handler; |
|||
|
|||
import com.zc.business.domain.DcTollStationStatisticsData; |
|||
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|||
import com.zc.business.mapper.DcTollStationStatisticsDataMapper; |
|||
import com.zc.business.service.IDcTollStationStatisticsDataService; |
|||
import com.zc.business.statistics.cache.AbstractTrafficStatisticsCache; |
|||
import com.zc.business.statistics.cache.tollstation.DailyTrafficTollStationStatisticsCache; |
|||
import com.zc.business.statistics.cache.tollstation.MonthlyTrafficTollStationStatisticsCache; |
|||
import com.zc.business.statistics.cache.tollstation.QuarterlyTrafficTollStationStatisticsCache; |
|||
import com.zc.business.statistics.cache.tollstation.YearlyTrafficTollStationStatisticsCache; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.util.CollectionUtils; |
|||
|
|||
import javax.annotation.Resource; |
|||
import java.util.Collection; |
|||
import java.util.Map; |
|||
import java.util.function.Consumer; |
|||
|
|||
/** |
|||
* TrafficTollStationStatistics类用于处理交通收费站的统计数据。 |
|||
* @author xiepufeng |
|||
*/ |
|||
@Component |
|||
public class TrafficTollStationStatistics { |
|||
|
|||
// 日志记录器
|
|||
protected final Logger logger = LoggerFactory.getLogger(this.getClass()); |
|||
|
|||
@Resource |
|||
private IDcTollStationStatisticsDataService dcTollStationStatisticsDataService; |
|||
|
|||
@Resource |
|||
private DcTollStationStatisticsDataMapper dcTollStationStatisticsDataMapper; |
|||
|
|||
|
|||
/** |
|||
* 定义每小时第20分钟执行的任务,用于清除过期缓存数据并将缓存中的数据整合后保存至数据库。 |
|||
*/ |
|||
@Scheduled(cron = "0 20 * * * ?") // 每小时的20分整点执行该任务
|
|||
public void performHourlyCleanupAndPersist() { |
|||
|
|||
// 添加日收费站站点数据到缓存中
|
|||
dcTollStationStatisticsDataService.lastHourData().forEach(DailyTrafficTollStationStatisticsCache::addCacheData); |
|||
|
|||
// 清除已过期的缓存数据
|
|||
DailyTrafficTollStationStatisticsCache.clearExpiredData(); |
|||
MonthlyTrafficTollStationStatisticsCache.clearExpiredData(); |
|||
QuarterlyTrafficTollStationStatisticsCache.clearExpiredData(); |
|||
YearlyTrafficTollStationStatisticsCache.clearExpiredData(); |
|||
|
|||
// 整合缓存数据并保存至数据库
|
|||
// 将缓存中的数据按日统计后保存至数据库
|
|||
// 添加月收费站站点数据到缓存中
|
|||
persistAggregatedData(DailyTrafficTollStationStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.DAY, MonthlyTrafficTollStationStatisticsCache::addCacheData); |
|||
// 将缓存中的数据按月统计后保存至数据库
|
|||
// 添加季度收费站站点数据到缓存中
|
|||
persistAggregatedData(MonthlyTrafficTollStationStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.MONTH, QuarterlyTrafficTollStationStatisticsCache::addCacheData); |
|||
// 将缓存中的数据按季度统计后保存至数据库
|
|||
// 添加年收费站站点数据到缓存中
|
|||
persistAggregatedData(QuarterlyTrafficTollStationStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.QUARTER, YearlyTrafficTollStationStatisticsCache::addCacheData); |
|||
// 将缓存中的数据按年统计后保存至数据库
|
|||
persistAggregatedData(YearlyTrafficTollStationStatisticsCache.getCache(), TrafficDataPeriodTypeEnum.YEAR, (a) -> {}); |
|||
} |
|||
|
|||
/** |
|||
* 将缓存中的数据统计后保存至数据库。 |
|||
*/ |
|||
public void persistAggregatedData( |
|||
Map<String, ? extends AbstractTrafficStatisticsCache<DcTollStationStatisticsData>> cache, |
|||
TrafficDataPeriodTypeEnum periodType, |
|||
Consumer<DcTollStationStatisticsData> consumer |
|||
) { |
|||
for (AbstractTrafficStatisticsCache<DcTollStationStatisticsData> data : cache.values()) { |
|||
// 如果数据已经存储过,则跳过此次处理
|
|||
if (data.isStored()) { |
|||
continue; |
|||
} |
|||
DcTollStationStatisticsData aggregatedData = trafficStatistics(data.getData(), periodType); |
|||
if (dcTollStationStatisticsDataMapper.insertOrUpdate(aggregatedData)) { |
|||
// 设置数据已存储状态
|
|||
data.setStored(true); |
|||
// 调用回调函数
|
|||
consumer.accept(aggregatedData); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 对给定的收费站点统计数据集合进行汇总处理。 |
|||
* |
|||
* @param dataCollection 收费站点统计数据的集合,不可为null或空。 |
|||
* @param trafficDataPeriodType 统计数据的时段类型,例如:小时、日、月等。 |
|||
* @return 汇总后的收费站点统计数据对象,如果输入数据为空则返回null。 |
|||
*/ |
|||
public DcTollStationStatisticsData trafficStatistics(Collection<DcTollStationStatisticsData> dataCollection, TrafficDataPeriodTypeEnum trafficDataPeriodType) { |
|||
|
|||
// 判断输入数据是否为空
|
|||
if (CollectionUtils.isEmpty(dataCollection)) { |
|||
return null; |
|||
} |
|||
|
|||
// 创建一个汇总统计用的对象
|
|||
DcTollStationStatisticsData aggregatedData = new DcTollStationStatisticsData(); |
|||
|
|||
// 初始化车流量总和
|
|||
int trafficVolume = 0; |
|||
|
|||
// 初始化1型客车车流量
|
|||
int type1PassengerFlow = 0; |
|||
// 初始化2型客车车流量
|
|||
int type2PassengerFlow = 0; |
|||
// 初始化3型客车车流量
|
|||
int type3PassengerFlow = 0; |
|||
// 初始化4型客车车流量
|
|||
int type4PassengerFlow = 0; |
|||
|
|||
// 初始化1型货车车流量
|
|||
int type1TruckFlow = 0; |
|||
// 初始化2型货车车流量
|
|||
int type2TruckFlow = 0; |
|||
// 初始化3型货车车流量
|
|||
int type3TruckFlow = 0; |
|||
// 初始化4型货车车流量
|
|||
int type4TruckFlow = 0; |
|||
// 初始化5型货车车流量
|
|||
int type5TruckFlow = 0; |
|||
// 初始化6型货车车流量
|
|||
int type6TruckFlow = 0; |
|||
|
|||
// 初始化1型专项作业车车流量
|
|||
int type1SpecialVehicleFlow = 0; |
|||
// 初始化2型专项作业车车流量
|
|||
int type2SpecialVehicleFlow = 0; |
|||
// 初始化3型专项作业车车流量
|
|||
int type3SpecialVehicleFlow = 0; |
|||
// 初始化4型专项作业车车流量
|
|||
int type4SpecialVehicleFlow = 0; |
|||
// 初始化5型专项作业车车流量
|
|||
int type5SpecialVehicleFlow = 0; |
|||
// 初始化6型专项作业车车流量
|
|||
int type6SpecialVehicleFlow = 0; |
|||
|
|||
|
|||
// 遍历数据集合,累加各类车辆的车流量
|
|||
for (DcTollStationStatisticsData data: dataCollection) { |
|||
// 累加车流量
|
|||
trafficVolume += data.getTrafficVolume(); |
|||
// 累加1型客车车流量
|
|||
type1PassengerFlow += data.getType1PassengerFlow(); |
|||
// 累加2型客车车流量
|
|||
type2PassengerFlow += data.getType2PassengerFlow(); |
|||
// 累加3型客车车流量
|
|||
type3PassengerFlow += data.getType3PassengerFlow(); |
|||
// 累加4型客车车流量
|
|||
type4PassengerFlow += data.getType4PassengerFlow(); |
|||
|
|||
// 累加1型货车车流量
|
|||
type1TruckFlow += data.getType1TruckFlow(); |
|||
// 累加2型货车车流量
|
|||
type2TruckFlow += data.getType2TruckFlow(); |
|||
// 累加3型货车车流量
|
|||
type3TruckFlow += data.getType3TruckFlow(); |
|||
// 累加4型货车车流量
|
|||
type4TruckFlow += data.getType4TruckFlow(); |
|||
// 累加5型货车车流量
|
|||
type5TruckFlow += data.getType5TruckFlow(); |
|||
// 累加6型货车车流量
|
|||
type6TruckFlow += data.getType6TruckFlow(); |
|||
|
|||
// 累加1型专项作业车车流量
|
|||
type1SpecialVehicleFlow += data.getType1SpecialVehicleFlow(); |
|||
// 累加2型专项作业车车流量
|
|||
type2SpecialVehicleFlow += data.getType2SpecialVehicleFlow(); |
|||
// 累加3型专项作业车车流量
|
|||
type3SpecialVehicleFlow += data.getType3SpecialVehicleFlow(); |
|||
// 累加4型专项作业车车流量
|
|||
type4SpecialVehicleFlow += data.getType4SpecialVehicleFlow(); |
|||
// 累加5型专项作业车车流量
|
|||
type5SpecialVehicleFlow += data.getType5SpecialVehicleFlow(); |
|||
// 累加6型专项作业车车流量
|
|||
type6SpecialVehicleFlow += data.getType6SpecialVehicleFlow(); |
|||
} |
|||
|
|||
// 使用第一个数据项的信息填充汇总统计对象的基本属性
|
|||
DcTollStationStatisticsData firstDcTrafficSectionData = dataCollection.iterator().next(); |
|||
|
|||
// 设置收费站站点标识
|
|||
aggregatedData.setTollStationCode(firstDcTrafficSectionData.getTollStationCode()); |
|||
// 设置统计时间
|
|||
aggregatedData.setStatisticalDate(firstDcTrafficSectionData.getStatisticalDate(), trafficDataPeriodType); |
|||
// 上报时间
|
|||
aggregatedData.setReportTime(firstDcTrafficSectionData.getReportTime()); |
|||
// 时段类型
|
|||
aggregatedData.setPeriodType(trafficDataPeriodType); |
|||
// 出入类型
|
|||
aggregatedData.setAccessType(firstDcTrafficSectionData.getAccessType()); |
|||
|
|||
// 车流量
|
|||
aggregatedData.setTrafficVolume(trafficVolume); |
|||
// 1型客车车流量
|
|||
aggregatedData.setType1PassengerFlow(type1PassengerFlow); |
|||
// 2型客车车流量
|
|||
aggregatedData.setType2PassengerFlow(type2PassengerFlow); |
|||
// 3型客车车流量
|
|||
aggregatedData.setType3PassengerFlow(type3PassengerFlow); |
|||
// 4型客车车流量
|
|||
aggregatedData.setType4PassengerFlow(type4PassengerFlow); |
|||
// 1型货车车流量
|
|||
aggregatedData.setType1TruckFlow(type1TruckFlow); |
|||
// 2型货车车流量
|
|||
aggregatedData.setType2TruckFlow(type2TruckFlow); |
|||
// 3型货车车流量
|
|||
aggregatedData.setType3TruckFlow(type3TruckFlow); |
|||
// 4型货车车流量
|
|||
aggregatedData.setType4TruckFlow(type4TruckFlow); |
|||
// 5型货车车流量
|
|||
aggregatedData.setType5TruckFlow(type5TruckFlow); |
|||
// 6型货车车流量
|
|||
aggregatedData.setType6TruckFlow(type6TruckFlow); |
|||
// 1型专项作业车车流量
|
|||
aggregatedData.setType1SpecialVehicleFlow(type1SpecialVehicleFlow); |
|||
// 2型专项作业车车流量
|
|||
aggregatedData.setType2SpecialVehicleFlow(type2SpecialVehicleFlow); |
|||
// 3型专项作业车车流量
|
|||
aggregatedData.setType3SpecialVehicleFlow(type3SpecialVehicleFlow); |
|||
// 4型专项作业车车流量
|
|||
aggregatedData.setType4SpecialVehicleFlow(type4SpecialVehicleFlow); |
|||
// 5型专项作业车车流量
|
|||
aggregatedData.setType5SpecialVehicleFlow(type5SpecialVehicleFlow); |
|||
// 6型专项作业车车流量
|
|||
aggregatedData.setType6SpecialVehicleFlow(type6SpecialVehicleFlow); |
|||
|
|||
// 生成主键
|
|||
aggregatedData.generateUniqueId(); |
|||
|
|||
return aggregatedData; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,91 @@ |
|||
<?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.DcGantryStatisticsDataMapper"> |
|||
|
|||
<!-- 插入或更新交通路段数据 --> |
|||
<insert id="insertOrUpdate" parameterType="com.zc.business.domain.DcGantryStatisticsData"> |
|||
INSERT INTO |
|||
dc_gantry_statistics_data |
|||
( |
|||
id, |
|||
gantry_code, |
|||
statistical_date, |
|||
traffic_volume, |
|||
period_type, |
|||
create_time, |
|||
type1_passenger_flow, |
|||
type2_passenger_flow, |
|||
type3_passenger_flow, |
|||
type4_passenger_flow, |
|||
type1_truck_flow, |
|||
type2_truck_flow, |
|||
type3_truck_flow, |
|||
type4_truck_flow, |
|||
type5_truck_flow, |
|||
type6_truck_flow, |
|||
type1_special_vehicle_flow, |
|||
type2_special_vehicle_flow, |
|||
type3_special_vehicle_flow, |
|||
type4_special_vehicle_flow, |
|||
type5_special_vehicle_flow, |
|||
type6_special_vehicle_flow |
|||
) |
|||
VALUES |
|||
( |
|||
#{id}, |
|||
#{gantryCode}, |
|||
#{statisticalDate}, |
|||
#{trafficVolume}, |
|||
#{periodType}, |
|||
NOW(), |
|||
#{type1PassengerFlow}, |
|||
#{type2PassengerFlow}, |
|||
#{type3PassengerFlow}, |
|||
#{type4PassengerFlow}, |
|||
#{type1TruckFlow}, |
|||
#{type2TruckFlow}, |
|||
#{type3TruckFlow}, |
|||
#{type4TruckFlow}, |
|||
#{type5TruckFlow}, |
|||
#{type6TruckFlow}, |
|||
#{type1SpecialVehicleFlow}, |
|||
#{type2SpecialVehicleFlow}, |
|||
#{type3SpecialVehicleFlow}, |
|||
#{type4SpecialVehicleFlow}, |
|||
#{type5SpecialVehicleFlow}, |
|||
#{type6SpecialVehicleFlow} |
|||
) |
|||
ON DUPLICATE KEY UPDATE |
|||
gantry_code = VALUES(gantry_code), |
|||
statistical_date = VALUES(statistical_date), |
|||
traffic_volume = VALUES(traffic_volume), |
|||
period_type = VALUES(period_type), |
|||
update_time = NOW(), |
|||
type1_passenger_flow = VALUES(type1_passenger_flow), |
|||
type2_passenger_flow = VALUES(type2_passenger_flow), |
|||
type3_passenger_flow = VALUES(type3_passenger_flow), |
|||
type4_passenger_flow = VALUES(type4_passenger_flow), |
|||
type1_truck_flow = VALUES(type1_truck_flow), |
|||
type2_truck_flow = VALUES(type2_truck_flow), |
|||
type3_truck_flow = VALUES(type3_truck_flow), |
|||
type4_truck_flow = VALUES(type4_truck_flow), |
|||
type5_truck_flow = VALUES(type5_truck_flow), |
|||
type6_truck_flow = VALUES(type6_truck_flow), |
|||
type1_special_vehicle_flow = VALUES(type1_special_vehicle_flow), |
|||
type2_special_vehicle_flow = VALUES(type2_special_vehicle_flow), |
|||
type3_special_vehicle_flow = VALUES(type3_special_vehicle_flow), |
|||
type4_special_vehicle_flow = VALUES(type4_special_vehicle_flow), |
|||
type5_special_vehicle_flow = VALUES(type5_special_vehicle_flow), |
|||
type6_special_vehicle_flow = VALUES(type6_special_vehicle_flow) |
|||
</insert> |
|||
|
|||
<select id="getMaxStatisticalDate" resultType="java.util.Date"> |
|||
SELECT |
|||
MAX(statistical_date) |
|||
FROM |
|||
dc_gantry_statistics_data |
|||
</select> |
|||
|
|||
</mapper> |
@ -0,0 +1,94 @@ |
|||
<?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.DcTollStationStatisticsDataMapper"> |
|||
|
|||
<!-- 插入或更新交通路段数据 --> |
|||
<insert id="insertOrUpdate" parameterType="com.zc.business.domain.DcTollStationStatisticsData"> |
|||
INSERT INTO |
|||
dc_toll_station_statistics_data |
|||
( |
|||
id, |
|||
toll_station_code, |
|||
statistical_date, |
|||
traffic_volume, |
|||
period_type, |
|||
access_type, |
|||
create_time, |
|||
type1_passenger_flow, |
|||
type2_passenger_flow, |
|||
type3_passenger_flow, |
|||
type4_passenger_flow, |
|||
type1_truck_flow, |
|||
type2_truck_flow, |
|||
type3_truck_flow, |
|||
type4_truck_flow, |
|||
type5_truck_flow, |
|||
type6_truck_flow, |
|||
type1_special_vehicle_flow, |
|||
type2_special_vehicle_flow, |
|||
type3_special_vehicle_flow, |
|||
type4_special_vehicle_flow, |
|||
type5_special_vehicle_flow, |
|||
type6_special_vehicle_flow |
|||
) |
|||
VALUES |
|||
( |
|||
#{id}, |
|||
#{tollStationCode}, |
|||
#{statisticalDate}, |
|||
#{trafficVolume}, |
|||
#{periodType}, |
|||
#{accessType}, |
|||
NOW(), |
|||
#{type1PassengerFlow}, |
|||
#{type2PassengerFlow}, |
|||
#{type3PassengerFlow}, |
|||
#{type4PassengerFlow}, |
|||
#{type1TruckFlow}, |
|||
#{type2TruckFlow}, |
|||
#{type3TruckFlow}, |
|||
#{type4TruckFlow}, |
|||
#{type5TruckFlow}, |
|||
#{type6TruckFlow}, |
|||
#{type1SpecialVehicleFlow}, |
|||
#{type2SpecialVehicleFlow}, |
|||
#{type3SpecialVehicleFlow}, |
|||
#{type4SpecialVehicleFlow}, |
|||
#{type5SpecialVehicleFlow}, |
|||
#{type6SpecialVehicleFlow} |
|||
) |
|||
ON DUPLICATE KEY UPDATE |
|||
toll_station_code = VALUES(toll_station_code), |
|||
statistical_date = VALUES(statistical_date), |
|||
traffic_volume = VALUES(traffic_volume), |
|||
period_type = VALUES(period_type), |
|||
access_type = VALUES(access_type), |
|||
update_time = NOW(), |
|||
type1_passenger_flow = VALUES(type1_passenger_flow), |
|||
type2_passenger_flow = VALUES(type2_passenger_flow), |
|||
type3_passenger_flow = VALUES(type3_passenger_flow), |
|||
type4_passenger_flow = VALUES(type4_passenger_flow), |
|||
type1_truck_flow = VALUES(type1_truck_flow), |
|||
type2_truck_flow = VALUES(type2_truck_flow), |
|||
type3_truck_flow = VALUES(type3_truck_flow), |
|||
type4_truck_flow = VALUES(type4_truck_flow), |
|||
type5_truck_flow = VALUES(type5_truck_flow), |
|||
type6_truck_flow = VALUES(type6_truck_flow), |
|||
type1_special_vehicle_flow = VALUES(type1_special_vehicle_flow), |
|||
type2_special_vehicle_flow = VALUES(type2_special_vehicle_flow), |
|||
type3_special_vehicle_flow = VALUES(type3_special_vehicle_flow), |
|||
type4_special_vehicle_flow = VALUES(type4_special_vehicle_flow), |
|||
type5_special_vehicle_flow = VALUES(type5_special_vehicle_flow), |
|||
type6_special_vehicle_flow = VALUES(type6_special_vehicle_flow) |
|||
</insert> |
|||
|
|||
<select id="getMaxStatisticalDate" resultType="java.util.Date"> |
|||
SELECT |
|||
MAX(statistical_date) |
|||
FROM |
|||
dc_toll_station_statistics_data |
|||
</select> |
|||
|
|||
</mapper> |
Loading…
Reference in new issue