Commit 45271677 authored by hanbing's avatar hanbing

路口事件数据接入Redis

parent 12711daa
package net.wanji.datacenter.config;
import net.wanji.datacenter.util.FastJson2JsonRedisSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
@EnableAutoConfiguration
public class RedisConfig extends CachingConfigurerSupport {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxTotal;
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
/**
* 获取Jedis连接工厂
* <p>用于创建Jedis对象</p>
* @return JedisPool
*/
@Bean
public JedisPool redisPoolFactory() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxTotal);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setTestOnBorrow(false);
jedisPoolConfig.setTestOnReturn(false);
return new JedisPool(jedisPoolConfig, host, port,timeout, password, database);
}
/**
* retemplate相关配置
* @param factory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//不开启事务
template.setEnableTransactionSupport(false);
// 值采用json序列化value
template.setValueSerializer(fastJson2JsonRedisSerializer());
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
/**
* 选择redis作为默认缓存工具
* @param redisConnectionFactory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration).build();
}
/**
* @description: 自定义Redis序列化类
* @date 2019/4/29 20:23
*/
@Bean
public RedisSerializer fastJson2JsonRedisSerializer() {
return new FastJson2JsonRedisSerializer(Object.class);
}
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private Integer redisPort;
@Bean
public Jedis jedis() {
Jedis jedis = new Jedis(redisHost, redisPort);
jedis.auth("Wanji300552");
return jedis;
}
}
\ No newline at end of file
package net.wanji.datacenter.constant;
/**
* @author duanruiming
* @date 2023/01/16 10:45
*/
public class Constant {
/**
* Redis存储Key前缀
*/
public static final String KEY_PREFIX = "utcsystem_";
/**
* 分隔符:减号
**/
public static final String SEPARATOR_MINUS = "-";
public static final String WEBSOCKET_TOPIC_EVENT_WARN = "eventWarn";
public static final String WEBSOCKET_TOPIC_SYS_SERVICE_STATUS = "sysStatus";
public static final String WEBSOCKET_TOPIC_CAR_TRAIL_INFO = "carTrailInfo";
// WebSocket自动解锁路口topic
public static final String WEBSOCKET_AUTO_UNLOCK = "autoUnlock";
}
package net.wanji.datacenter.constant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* @ClassName EventAbnormalEnum
* @Description
* @Date 2021/4/15 11:13
* @Version 1.0
*/
public enum EventAbnormalEnum {
//机动车违停
ILLEGALSTOP("1","机动车违停",1,3),
//非机动车逆行
NONMOTORETROGRADE("2","非机动车逆行",1,2),
//机动车逆行
RETROGRADE("3","机动车逆行",1,2),
//占用专用车道
OCCUPYEXCLUSIVELANE("4","占用专用车道",1,1),
//行人在机动车道逗留
PEDESTRIANSTAYINVEHICLELANE("5","行人在机动车道逗留",1,1),
//机动车超速
VEHICLEOVERSPEED("6","机动车超速",1,1),
//非机动车超速
NONMOTOOVERSPEED("7","非机动车超速",1,1),
//机动车慢行
VEHICLESLOW("8","机动车慢行",1,1),
//机动车压线
VEHICLELINEPRESS("9","机动车压线",1,1),
//非机动车横穿马路
NONMOTOCROSSROAD("10","非机动车横穿马路",1,1),
//行人横穿马路
PEDESTRIANCROSSROAD("11","行人横穿马路",1,3),
//机动车横穿马路
VEHICLECROSSROAD("12","机动车横穿马路",1,1),
//机动车闯红灯
VEHICLERUNREDLIGHT("13","机动车闯红灯",0.5,2),
//行人闯红灯
PEDESTRIANRUNREDLIGHT("14","行人闯红灯",1,2),
//占用公交车道
OCCUPYBUSLANE("15","占用公交车道",0.5,2),
//变道
CHANGELANE("16","实线违规变道",0.5,2),
//遗撒物
LITTER("17","遗撒物",1,3),
//交通事故
TRAFFICACCIDENT("18","交通事故",0.5,2),
//占用应急车道
OCCUPYEMERGENCYLANE("19","占用应急车道",1,1),
//隧道悬臂物
CANTILEVER("20","隧道悬臂物",1,1),
//行人进入隧道
PEDESTRIANENTERTUNNEL("21","行人进入隧道",1,1),
//非机动车进入隧道
NONMOTOENTERTUNNEL("22","非机动车进入隧道",1,1),
//非机动车越线停车
NONMOTO_PARK_ON_LINE("23","非机动车越线停车",1,3),
// 非机动车占用机动车道
NONMOTO_RUN_IN_OTHER_LINE("24","非机动车占用机动车道",1,2),
// 非机动车闯红灯
NONMOTO_RUN_REDLIGHT("25","非机动车闯红灯",1,2),
// 非机动车载人
NONMOTO_CARRY_PEOPLE("26","非机动车载人",1,1),
// 机动车不按车道方向行驶
MOTO_RUN_WRONG_DIRECTION("27","机动车不按车道方向行驶",1,1),
// 机动车占用非机动车道
MOTO_RUN_IN_OTHER_LINE("28","机动车占用非机动车道",1,2),
// 机动车越线停车
MOTO_PARK_ON_LINE("29","机动车越线停车",0.5,2),
// 施工
CONSTRUCTION("30","施工",1,3),
// 机动车未礼让行人
MOTO_NO_YIEDLD_PEDESTRIAN("31","机动车未礼让行人",0.5,2),
// 限号出行【大屏需求改为货车限行】
RESTRICTION_LICENSE_PLATE("32","机动车限号出行",0.5,2),
RAPID_ACCELERATION("33", "急加速",1,1),
RAPID_DECELERATION("34", "急减速",1,1),
SHARP_TURN("35", "急转弯",1,1),
//能见度异常
ABNORMALVISIBILITY("101","能见度异常",1,1),
//光强异常
ABNORMALLIGHT("102","光强异常",1,1),
//CO异常
ABNORMALCO("103","CO异常",1,1),
//火灾
FIR("104","火灾",1,1),
// ***** 事故
ACCIDENT_YS("401","疑似事故",1,1),
ACCIDENT_ONE_YS("402","疑似单车事故",1,1),
ACCIDENT_TWO_YS("403","疑似双车事故",1,1),
ACCIDENT_MORE_YS("404","疑似多车事故",1,1),
// ***** 拥堵
NO_CONGEST("501","畅通",1,1),
LIGHT_CONGEST("502","轻微拥堵",1,1),
MODERATE_CONGEST("503","中度拥堵",1,1),
HEAVY_CONGEST("504","重度拥堵",1,1),
PHASE_EMPTY("701","相位空放",1,1),
CROSS_UNBALANCE("702","路口失衡",1,1),
CROSS_OVERFLOW("703","路口溢出",1,1),
CROSS_DEADLOCK("704","路口死锁",1,1),
/*危险驾驶*/
CONFLICT_POINT("601", "冲突点",1,1),
OVERFLOW_CONGESTION("605", "路口溢出",1,1),
ROADSEGMENT_U_TURN("606", "路段掉头",1,1),
DANGER_S_DRIVER("607", "危险驾驶-S形驾驶",1,1),
ABNORMAL_STOP_CAR("608", "异常停车",1,1)
;
public final static double step_default = 1;
String type;
String desc;
double step_turn; // 转向时步长 s
double step_noTurn; // 无转向时步长 s
EventAbnormalEnum(String type, String desc, double step_turn, double step_noTurn) {
this.type = type;
this.desc = desc;
this.step_turn = step_turn;
this.step_noTurn = step_noTurn;
//命令字
}
public String getType(){
return type;
}
public String getDesc() {
return desc;
}
public double getStep_turn() {
return step_turn;
}
public double getStep_noTurn() {
return step_noTurn;
}
public static EventAbnormalEnum getByType(String type){
for (EventAbnormalEnum abnormalEnum : EventAbnormalEnum.values()) {
if(abnormalEnum.getType().equals(type)){
return abnormalEnum;
}
}
return null;
}
//隐患事件类型
public static final List<EventAbnormalEnum> HiddenDangerEvents = Arrays.asList(
new EventAbnormalEnum[] {
EventAbnormalEnum.CONFLICT_POINT,
EventAbnormalEnum.RAPID_ACCELERATION,
EventAbnormalEnum.RAPID_DECELERATION,
EventAbnormalEnum.SHARP_TURN,
EventAbnormalEnum.OVERFLOW_CONGESTION,
EventAbnormalEnum.ROADSEGMENT_U_TURN,
EventAbnormalEnum.DANGER_S_DRIVER,
EventAbnormalEnum.MOTO_NO_YIEDLD_PEDESTRIAN,
EventAbnormalEnum.MOTO_RUN_WRONG_DIRECTION,
EventAbnormalEnum.ABNORMAL_STOP_CAR
}
);
//违法事件类型
public static final List<EventAbnormalEnum> IllegalEvents = Arrays.asList(
new EventAbnormalEnum[] {
EventAbnormalEnum.CHANGELANE,
EventAbnormalEnum.ILLEGALSTOP,
EventAbnormalEnum.VEHICLERUNREDLIGHT,
EventAbnormalEnum.VEHICLEOVERSPEED,
EventAbnormalEnum.RETROGRADE
}
);
//事故事件类型
public static final List<EventAbnormalEnum> AccidentEvents = Arrays.asList(
new EventAbnormalEnum[] {
EventAbnormalEnum.ACCIDENT_ONE_YS,
EventAbnormalEnum.ACCIDENT_TWO_YS,
EventAbnormalEnum.ACCIDENT_MORE_YS
}
);
// 机动车事件
public static final List<EventAbnormalEnum> VehicleEvents = Arrays.asList(new EventAbnormalEnum[]{
EventAbnormalEnum.ILLEGALSTOP,
EventAbnormalEnum.RETROGRADE,
EventAbnormalEnum.OCCUPYEXCLUSIVELANE,
EventAbnormalEnum.VEHICLEOVERSPEED,
EventAbnormalEnum.VEHICLESLOW,
EventAbnormalEnum.VEHICLELINEPRESS,
EventAbnormalEnum.VEHICLECROSSROAD,
EventAbnormalEnum.VEHICLERUNREDLIGHT,
EventAbnormalEnum.OCCUPYBUSLANE,
EventAbnormalEnum.CHANGELANE,
EventAbnormalEnum.OCCUPYEMERGENCYLANE,
EventAbnormalEnum.MOTO_RUN_WRONG_DIRECTION,
EventAbnormalEnum.MOTO_RUN_IN_OTHER_LINE,
EventAbnormalEnum.MOTO_PARK_ON_LINE,
EventAbnormalEnum.MOTO_NO_YIEDLD_PEDESTRIAN,
EventAbnormalEnum.RESTRICTION_LICENSE_PLATE,
EventAbnormalEnum.RAPID_ACCELERATION,
EventAbnormalEnum.RAPID_DECELERATION,
EventAbnormalEnum.SHARP_TURN
});
// 非机动车事件
public static final List<EventAbnormalEnum> NonVehicleEvents = Arrays.asList(new EventAbnormalEnum[]{
EventAbnormalEnum.NONMOTORETROGRADE,
EventAbnormalEnum.NONMOTOOVERSPEED,
EventAbnormalEnum.NONMOTOCROSSROAD,
EventAbnormalEnum.NONMOTOENTERTUNNEL,
EventAbnormalEnum.NONMOTO_PARK_ON_LINE,
EventAbnormalEnum.NONMOTO_RUN_IN_OTHER_LINE,
EventAbnormalEnum.NONMOTO_RUN_REDLIGHT,
EventAbnormalEnum.NONMOTO_CARRY_PEOPLE
});
// 行人事件
public static final List<EventAbnormalEnum> PedestrianentEvents = Arrays.asList(new EventAbnormalEnum[]{
EventAbnormalEnum.PEDESTRIANSTAYINVEHICLELANE,
EventAbnormalEnum.PEDESTRIANCROSSROAD,
EventAbnormalEnum.PEDESTRIANRUNREDLIGHT,
EventAbnormalEnum.PEDESTRIANENTERTUNNEL
});
// 拥堵事件
public static final List<EventAbnormalEnum> CongestionEvents = Arrays.asList(new EventAbnormalEnum[]{
EventAbnormalEnum.NO_CONGEST,
EventAbnormalEnum.LIGHT_CONGEST,
EventAbnormalEnum.MODERATE_CONGEST,
EventAbnormalEnum.HEAVY_CONGEST
});
/**
* 是否为 机动车事件
* @param type 车辆类型
* @return
*/
public static boolean isVehicleEvent(String type){
return VehicleEvents.stream().anyMatch(event -> event.getType().equals(type));
}
/**
* 是否为 机动车闯红灯
* @param type 车辆类型
* @return
*/
public static boolean isVehicleEvent_runRedlight(String type){
return EventAbnormalEnum.VEHICLERUNREDLIGHT.type.equals(type);
}
/**
* 是否为 机动车越线停车
* @param type 车辆类型
* @return
*/
public static boolean isVehicleEvent_parkOnLine(String type){
return EventAbnormalEnum.MOTO_PARK_ON_LINE.type.equals(type);
}
/**
* 是否为 机动车不按车道方向行驶
* @param type 车辆类型
* @return
*/
public static boolean isVehicleEvent_runWrongDirection(String type){
return EventAbnormalEnum.MOTO_RUN_WRONG_DIRECTION.type.equals(type);
}
/**
* 是否为 机动车占用非机动车道
* @param type 车辆类型
* @return
*/
public static boolean isVehicleEvent_runInOtherLine(String type){
return EventAbnormalEnum.MOTO_RUN_IN_OTHER_LINE.type.equals(type);
}
/**
* 是否为 机动车未礼让行人
* @param type 车辆类型
* @return
*/
public static boolean isVehicleEvent_NoYiedldPedestrian(String type){
return EventAbnormalEnum.MOTO_NO_YIEDLD_PEDESTRIAN.type.equals(type);
}
/**
* 是否为 非机动车事件
* @param type 车辆类型
* @return
*/
public static boolean isNonVehicleEvent(String type){
return NonVehicleEvents.stream().anyMatch(event -> event.getType().equals(type));
}
/**
* 是否为 非机动车闯红灯
* @param type 车辆类型
* @return
*/
public static boolean isNonVehicleEvent_runRedlight(String type){
return EventAbnormalEnum.NONMOTO_RUN_REDLIGHT.type.equals(type);
}
/**
* 是否为 非机动车逆行
* @param type 车辆类型
* @return
*/
public static boolean isNonVehicleEvent_retrograde(String type){
return EventAbnormalEnum.NONMOTORETROGRADE.type.equals(type);
}
/**
* 是否为 非机动车占用机动车道
* @param type 车辆类型
* @return
*/
public static boolean isNonVehicleEvent_runInOtherLine(String type){
return EventAbnormalEnum.NONMOTO_RUN_IN_OTHER_LINE.type.equals(type);
}
/**
* 是否为 非机动车越线停车
* @param type 车辆类型
* @return
*/
public static boolean isNonVehicleEvent_parkOnLine(String type){
return EventAbnormalEnum.NONMOTO_PARK_ON_LINE.type.equals(type);
}
/**
* 是否为 非机动车违规载人
* @param type 车辆类型
* @return
*/
public static boolean isNonVehicleEvent_carryPeople(String type){
return EventAbnormalEnum.NONMOTO_CARRY_PEOPLE.type.equals(type);
}
/**
* 是否为 行人事件
* @param type 车辆类型
* @return
*/
public static boolean isPedestrianentEvent(String type){
return PedestrianentEvents.stream().anyMatch(event -> event.getType().equals(type));
}
/**
* 是否为 行人闯红灯
* @param type 车辆类型
* @return
*/
public static boolean isPedestrianentEvent_runRedlight(String type){
return EventAbnormalEnum.PEDESTRIANRUNREDLIGHT.type.equals(type);
}
/**
* 是否为 行人横穿马路
* @param type 车辆类型
* @return
*/
public static boolean isPedestrianentEvent_crossroad(String type){
return EventAbnormalEnum.PEDESTRIANCROSSROAD.type.equals(type);
}
/**
* 是否为 事故
* @return
*/
public static boolean isAccidentEvent(String type){
return EventAbnormalEnum.ACCIDENT_YS.type.equals(type);
}
/**
* 是否为 拥堵
* @return
*/
public static boolean isCongestionEvent(String type){
return CongestionEvents.stream().anyMatch(event -> event.getType().equals(type));
}
//事件子类型
public static List<String> getEventTypeList(String eventCategory) {
List<EventAbnormalEnum> enumList = new ArrayList<>();
if (Objects.equals("4", eventCategory)) {
enumList = EventAbnormalEnum.AccidentEvents;
} else if (Objects.equals("6", eventCategory)) {
enumList = EventAbnormalEnum.HiddenDangerEvents;
} else if (Objects.equals("7", eventCategory)) {
enumList = EventAbnormalEnum.IllegalEvents;
} else {
enumList.addAll(EventAbnormalEnum.AccidentEvents);
enumList.addAll(EventAbnormalEnum.HiddenDangerEvents);
enumList.addAll(EventAbnormalEnum.IllegalEvents);
}
List<String> list = new ArrayList<>();
for (EventAbnormalEnum eventEnum : enumList) {
list.add(eventEnum.getType());
}
return list;
}
}
package net.wanji.datacenter.kafka; package net.wanji.datacenter.kafka;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.wanji.common.utils.tool.JacksonUtils;
import net.wanji.datacenter.constant.EventAbnormalEnum;
import net.wanji.datacenter.pojo.dto.CrossEventDTO;
import net.wanji.datacenter.pojo.dto.CrossLaneSnapshotDataDTO; import net.wanji.datacenter.pojo.dto.CrossLaneSnapshotDataDTO;
import net.wanji.datacenter.pojo.dto.CrossSnapshotDataDTO; import net.wanji.datacenter.pojo.dto.CrossSnapshotDataDTO;
import net.wanji.datacenter.service.DataProcessService; import net.wanji.datacenter.service.DataProcessService;
import net.wanji.datacenter.util.RedisUtils;
import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.listener.KafkaListenerErrorHandler; import org.springframework.kafka.listener.KafkaListenerErrorHandler;
import org.springframework.kafka.listener.ListenerExecutionFailedException; import org.springframework.kafka.listener.ListenerExecutionFailedException;
...@@ -19,6 +25,7 @@ import javax.annotation.Resource; ...@@ -19,6 +25,7 @@ import javax.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
...@@ -29,6 +36,8 @@ import java.util.concurrent.ConcurrentHashMap; ...@@ -29,6 +36,8 @@ import java.util.concurrent.ConcurrentHashMap;
@Slf4j @Slf4j
public class ConsumerHandler implements KafkaListenerErrorHandler { public class ConsumerHandler implements KafkaListenerErrorHandler {
// Redis缓存过期时间
public static final int TTL_IN_MILLIS = 10 * 60 * 1000;
@Resource(name = "lanePeriodicDataProcessService") @Resource(name = "lanePeriodicDataProcessService")
DataProcessService lanePeriodicDataProcessService; DataProcessService lanePeriodicDataProcessService;
@Resource(name = "crossSnapshotDataProcessService") @Resource(name = "crossSnapshotDataProcessService")
...@@ -36,10 +45,13 @@ public class ConsumerHandler implements KafkaListenerErrorHandler { ...@@ -36,10 +45,13 @@ public class ConsumerHandler implements KafkaListenerErrorHandler {
@Resource(name = "laneSnapshotDataProcessService") @Resource(name = "laneSnapshotDataProcessService")
DataProcessService laneSnapshotDataProcessService; DataProcessService laneSnapshotDataProcessService;
@Autowired
RedisUtils redisUtils;
public static final Map<String, List<CrossSnapshotDataDTO>> crossSnapshotDataMap = new ConcurrentHashMap<>(); public static final Map<String, List<CrossSnapshotDataDTO>> crossSnapshotDataMap = new ConcurrentHashMap<>();
@KafkaListener(topics = {"JN050001LanePeriodicData"}, groupId = "group") @KafkaListener(topics = {"JN050001LanePeriodicData"}, groupId = "group")
public void receiveLanePeriodicData(ConsumerRecord<Object, Object> record, Acknowledgment acknowledgment) throws Exception{ public void receiveLanePeriodicData(ConsumerRecord<Object, Object> record, Acknowledgment acknowledgment) throws Exception {
Object convert = lanePeriodicDataProcessService.convert(String.valueOf(record.value())); Object convert = lanePeriodicDataProcessService.convert(String.valueOf(record.value()));
// 修改逻辑,将保存逻辑改为将方向,转向数据返回kafka // 修改逻辑,将保存逻辑改为将方向,转向数据返回kafka
lanePeriodicDataProcessService.save(convert); lanePeriodicDataProcessService.save(convert);
...@@ -77,6 +89,64 @@ public class ConsumerHandler implements KafkaListenerErrorHandler { ...@@ -77,6 +89,64 @@ public class ConsumerHandler implements KafkaListenerErrorHandler {
acknowledgment.acknowledge(); acknowledgment.acknowledge();
} }
@KafkaListener(topics = {"cross.event.index"}, groupId = "group2")
public void receiveCrossEventData(ConsumerRecord<Object, Object> record, Acknowledgment acknowledgment)
throws Exception {
try {
ObjectMapper objectMapper = new ObjectMapper();
String recordStr = String.valueOf(record.value());
CrossEventDTO crossEventDTO = JacksonUtils.getInstance().readValue(recordStr, CrossEventDTO.class);
String msgType = crossEventDTO.getMsgType();
String crossId = crossEventDTO.getCrossId();
if (Objects.equals(msgType, EventAbnormalEnum.CROSS_UNBALANCE.getType())) {
String redisListElement = objectMapper.writeValueAsString(crossEventDTO);
// 失衡事件
// 方向缓存
Integer unbalanceDir = crossEventDTO.getUnbalanceDir();
String redisKey = crossId + ":" + unbalanceDir;
redisUtils.addToSortedSetWithExpiry(redisKey, redisListElement, TTL_IN_MILLIS);
// 路口缓存
redisUtils.addToSortedSetWithExpiry(crossId, redisListElement, TTL_IN_MILLIS);
} else if (msgType.startsWith("50")) {
// 拥堵事件
// 方向缓存
List<CrossEventDTO> details = crossEventDTO.getDetails();
for (CrossEventDTO detail : details) {
detail.setMsgType(detail.getCongestionCode());
Integer dir = detail.getDir();
String redisKey = crossId + ":" + dir;
String redisListElement = objectMapper.writeValueAsString(detail);
redisUtils.addToSortedSetWithExpiry(redisKey, redisListElement, TTL_IN_MILLIS);
}
// 路口缓存
String redisListElement = objectMapper.writeValueAsString(crossEventDTO);
redisUtils.addToSortedSetWithExpiry(crossId, redisListElement, TTL_IN_MILLIS);
} else if (Objects.equals(msgType, EventAbnormalEnum.CROSS_OVERFLOW.getType())
|| Objects.equals(msgType, EventAbnormalEnum.CROSS_DEADLOCK.getType())) {
// 溢出和死锁事件
// 方向缓存
List<CrossEventDTO> details = crossEventDTO.getDetails();
for (CrossEventDTO detail : details) {
detail.setMsgType(EventAbnormalEnum.CROSS_OVERFLOW.getType());
Integer dir = detail.getDir();
String redisKey = crossId + ":" + dir;
String redisListElement = objectMapper.writeValueAsString(detail);
redisUtils.addToSortedSetWithExpiry(redisKey, redisListElement, TTL_IN_MILLIS);
}
// 路口缓存
String redisListElement = objectMapper.writeValueAsString(crossEventDTO);
redisUtils.addToSortedSetWithExpiry(crossId, redisListElement, TTL_IN_MILLIS);
}
} catch (Exception e) {
log.error("Kafka收到路口事件数据异常", e);
throw new Exception(e);
}
acknowledgment.acknowledge();
}
@Override @Override
@NonNull @NonNull
public Object handleError(Message<?> message, ListenerExecutionFailedException e) { public Object handleError(Message<?> message, ListenerExecutionFailedException e) {
......
package net.wanji.datacenter.pojo.dto;
import lombok.Data;
import java.util.List;
@Data
public class CrossEventDTO {
private Integer dir;
private String rid;
//该路段的结束路口
private String crossId;
private Double index;
private String indexName;
// 501畅通 502轻微拥堵 503中度拥堵 504重度拥堵
private String congestionCode;
private String timestamp;
private Long globalTimeStamp;
private Long startTime;
private Long endTime;
private Integer duration;
// 事件序列号
private String eventSerialNumber;
// 检测时间
private Long detectTime;
private List<CrossEventDTO> details;
private String msgType;
// 失衡方向
private Integer unbalanceDir;
}
...@@ -98,22 +98,27 @@ public class LanePeriodicDataProcessServiceImpl implements DataProcessService { ...@@ -98,22 +98,27 @@ public class LanePeriodicDataProcessServiceImpl implements DataProcessService {
List<CrossDirDataRealtimePO> crossDirDataRealtimePOS = new ArrayList<>(laneNum); List<CrossDirDataRealtimePO> crossDirDataRealtimePOS = new ArrayList<>(laneNum);
List<CrossTurnDataRealtimePO> crossTurnDataRealtimePOS = new ArrayList<>(laneNum); List<CrossTurnDataRealtimePO> crossTurnDataRealtimePOS = new ArrayList<>(laneNum);
List<CrossLaneDataRealTimePO> crossLaneDataRealTimePOS = new ArrayList<>(laneNum); List<CrossLaneDataRealTimePO> crossLaneDataRealTimePOS = new ArrayList<>(laneNum);
List<LanePeriodicDataDTO.EventList> eventLists = lanePeriodicDataDTO.getEventList(); List<LanePeriodicDataDTO.EventList> eventLists = lanePeriodicDataDTO.getEventList();
String timeStamp = lanePeriodicDataDTO.getTimeStamp(); String timeStamp = lanePeriodicDataDTO.getTimeStamp();
Date endDate = DateUtil.parse(timeStamp, DateStyle.YYYY_MM_DD_HH_MM_SS.getValue()); Date endDate = DateUtil.parse(timeStamp, DateStyle.YYYY_MM_DD_HH_MM_SS.getValue());
Date startDate = DateUtil.offsetMinute(endDate, -5); Date startDate = DateUtil.offsetMinute(endDate, -5);
if (CollectionUtils.isEmpty(eventLists)) { if (CollectionUtils.isEmpty(eventLists)) {
log.error("当前车道周期实时数据车道列表为空,参数信息:", lanePeriodicDataDTO); log.error("当前车道周期实时数据车道列表为空,参数信息:", lanePeriodicDataDTO);
throw new Exception("当前车道周期实时数据车道列表为空"); throw new Exception("当前车道周期实时数据车道列表为空");
} }
// 通过车道编号获取车道信息 // 通过车道编号获取车道信息
List<String> LaneIdList = eventLists.stream().map(LanePeriodicDataDTO.EventList::getLaneId).collect(Collectors.toList()); List<String> LaneIdList = eventLists.stream()
.map(LanePeriodicDataDTO.EventList::getLaneId)
.collect(Collectors.toList());
List<CrossBaseLaneInfoPO> crossBaseLaneInfoPOS = crossBaseLaneInfoMapper.selectBatchIds(LaneIdList); List<CrossBaseLaneInfoPO> crossBaseLaneInfoPOS = crossBaseLaneInfoMapper.selectBatchIds(LaneIdList);
DecimalFormat decimalFormat = new DecimalFormat("#.##"); DecimalFormat decimalFormat = new DecimalFormat("#.##");
// 将kafka车道数据与路口车道数据对应,获取路口编号,方向,转向,分组计算 // 将kafka车道数据与路口车道数据对应,获取路口编号,方向,转向,分组计算
for (LanePeriodicDataDTO.EventList laneRealTimeItem : eventLists) { for (LanePeriodicDataDTO.EventList laneRealTimeItem : eventLists) {
String laneId = laneRealTimeItem.getLaneId(); String laneId = laneRealTimeItem.getLaneId();
for (CrossBaseLaneInfoPO laneInfoPO : crossBaseLaneInfoPOS) { for (CrossBaseLaneInfoPO laneInfoPO : crossBaseLaneInfoPOS) {
String id = laneInfoPO.getId(); String id = laneInfoPO.getId();
if (StringUtils.equals(laneId, id)) { if (StringUtils.equals(laneId, id)) {
...@@ -270,11 +275,13 @@ public class LanePeriodicDataProcessServiceImpl implements DataProcessService { ...@@ -270,11 +275,13 @@ public class LanePeriodicDataProcessServiceImpl implements DataProcessService {
DecimalFormat decimalFormat, ProducerHandler producerHandler, Date startDate) throws Exception { DecimalFormat decimalFormat, ProducerHandler producerHandler, Date startDate) throws Exception {
// 方向数据 // 方向数据
List<CrossDirDataRealtimePO> insertCrossDirDataRealtimePOS = new ArrayList<>(); List<CrossDirDataRealtimePO> insertCrossDirDataRealtimePOS = new ArrayList<>();
Map<String, List<CrossDirDataRealtimePO>> crossDirDataRealTimePOSMap = crossDirDataRealtimePOS.stream().collect(Collectors.groupingBy(CrossDirDataRealtimePO::getCrossId)); Map<String, List<CrossDirDataRealtimePO>> crossDirDataRealTimePOSMap = crossDirDataRealtimePOS.stream()
.collect(Collectors.groupingBy(CrossDirDataRealtimePO::getCrossId));
for (Map.Entry<String, List<CrossDirDataRealtimePO>> entry : crossDirDataRealTimePOSMap.entrySet()) { for (Map.Entry<String, List<CrossDirDataRealtimePO>> entry : crossDirDataRealTimePOSMap.entrySet()) {
String crossId = entry.getKey(); String crossId = entry.getKey();
List<CrossDirDataRealtimePO> value = entry.getValue(); List<CrossDirDataRealtimePO> value = entry.getValue();
Map<Integer, List<CrossDirDataRealtimePO>> crossIdMap = value.stream().collect(Collectors.groupingBy(CrossDirDataRealtimePO::getDirType)); Map<Integer, List<CrossDirDataRealtimePO>> crossIdMap = value.stream()
.collect(Collectors.groupingBy(CrossDirDataRealtimePO::getDirType));
Double congestionIndex = 0.0; Double congestionIndex = 0.0;
Double spilloverIndex = 0.0; Double spilloverIndex = 0.0;
Double saturationAverage = 0.0; Double saturationAverage = 0.0;
...@@ -448,7 +455,7 @@ public class LanePeriodicDataProcessServiceImpl implements DataProcessService { ...@@ -448,7 +455,7 @@ public class LanePeriodicDataProcessServiceImpl implements DataProcessService {
if (delayTimeIndexMin <= 0.0) { if (delayTimeIndexMin <= 0.0) {
delayTimeIndexMin = 1.0; delayTimeIndexMin = 1.0;
} }
// 负载均衡 // 负载均衡
Double loadBalance = Math.sqrt(saturationSum / crossIdMap.size()); Double loadBalance = Math.sqrt(saturationSum / crossIdMap.size());
CrossDataIndexDTO crossDataIndexDTO = new CrossDataIndexDTO(); CrossDataIndexDTO crossDataIndexDTO = new CrossDataIndexDTO();
crossDataIndexDTO.setCongestionIndex(Double.valueOf(decimalFormat.format(congestionIndex))); crossDataIndexDTO.setCongestionIndex(Double.valueOf(decimalFormat.format(congestionIndex)));
......
package net.wanji.datacenter.task;
import lombok.extern.slf4j.Slf4j;
import net.wanji.datacenter.util.RedisUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Set;
/**
* @author Kent HAN
* @date 2023/12/15 16:41
*/
@Component
@Slf4j
public class RedisTask {
@Resource
private RedisUtils redisUtils;
/**
* 每分钟清理路口事件缓存
* @author Kent HAN
* @date 2023/12/15 16:42
*/
@Scheduled(fixedRate = 1000 * 60)
public void cleanCrossEventCache() throws Exception {
try {
Set<String> keys = redisUtils.keys();
for (String key : keys) {
redisUtils.removeExpiredElements(key);
}
} catch (Exception e) {
log.error("清理路口事件缓存失败", e);
throw new Exception(e);
}
}
}
package net.wanji.datacenter.util;
/**
* @author wanji
* @version 1.0
* @Description: [日期风格工具类]
* Created on 2019/4/16 15:07
*/
public enum DateStyle {
YYYY_MM("yyyy-MM", false),
YYYY_MM_DD("yyyy-MM-dd", false),
YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm", false),
YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss", false),
YYYYMMDDHHMMSS("yyyyMMddHHmmss", false),
YYYYMMDDHHMMSSSSS("yyyyMMddHHmmssSSS", false),
YYYYMMDD("yyyyMMdd", false),
YYYY_MM_EN("yyyy/MM", false),
YYYY_MM_DD_EN("yyyy/MM/dd", false),
YYYY_MM_DD_HH_MM_EN("yyyy/MM/dd HH:mm", false),
YYYY_MM_DD_HH_MM_SS_EN("yyyy/MM/dd HH:mm:ss", false),
DD_MM_YYYY_EN("dd/MM/yyyy", false),
YYYY_MM_CN("yyyy年MM月", false),
YYYY_MM_DD_CN("yyyy年MM月dd日", false),
YYYY_MM_DD_HH_MM_CN("yyyy年MM月dd日 HH:mm", false),
YYYY_MM_DD_HH_MM_SS_CN("yyyy年MM月dd日 HH:mm:ss", false),
HH_MM("HH:mm", true),
HH_MM_SS("HH:mm:ss", true),
MM_DD("MM-dd", true),
MM_DD_HH_MM("MM-dd HH:mm", true),
MM_DD_HH_MM_SS("MM-dd HH:mm:ss", true),
MM_DD_EN("MM/dd", true),
MM_DD_HH_MM_EN("MM/dd HH:mm", true),
MM_DD_HH_MM_SS_EN("MM/dd HH:mm:ss", true),
MM_DD_CN("MM月dd日", true),
MM_DD_HH_MM_CN("MM月dd日 HH:mm", true),
MM_DD_HH_MM_SS_CN("MM月dd日 HH:mm:ss", true);
private String value;
private boolean isShowOnly;
DateStyle(String value, boolean isShowOnly) {
this.value = value;
this.isShowOnly = isShowOnly;
}
public String getValue() {
return value;
}
public boolean isShowOnly() {
return isShowOnly;
}
}
\ No newline at end of file
package net.wanji.datacenter.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author wanji
* @version 1.0
* Created on 2019/4/16 15:28
* @Description: [日期工具类]
*/
@Slf4j
public class DateUtils {
private static final ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<>();
private static final Object object = new Object();
private DateUtils() {}
/**
* 获取SimpleDateFormat
*
* @param pattern 日期格式
* @return SimpleDateFormat对象
* @throws RuntimeException 异常:非法日期格式
*/
public static SimpleDateFormat getDateFormat(String pattern) {
SimpleDateFormat dateFormat = threadLocal.get();
if (dateFormat == null) {
synchronized (object) {
dateFormat = new SimpleDateFormat(pattern);
dateFormat.setLenient(false);
threadLocal.set(dateFormat);
}
}
dateFormat.applyPattern(pattern);
return dateFormat;
}
/**
* 获取日期中的某数值。如获取月份
*
* @param date 日期
* @param dateType 日期格式
* @return 数值
*/
private static int getInteger(Date date, int dateType) {
int num = 0;
Calendar calendar = Calendar.getInstance();
if (date != null) {
calendar.setTime(date);
num = calendar.get(dateType);
}
return num;
}
/**
* 增加日期中某类型的某数值。如增加日期
*
* @param date 日期字符串
* @param dateType 类型
* @param amount 数值
* @return 计算后日期字符串
*/
private static String addInteger(String date, int dateType, int amount) {
String dateString = null;
DateStyle dateStyle = getDateStyle(date);
if (dateStyle != null) {
Date myDate = stringToDate(date, dateStyle);
myDate = addInteger(myDate, dateType, amount);
dateString = dateToString(myDate, dateStyle);
}
return dateString;
}
/**
* 增加日期中某类型的某数值。如增加日期
*
* @param date 日期
* @param dateType 类型
* @param amount 数值
* @return 计算后日期
*/
private static Date addInteger(Date date, int dateType, int amount) {
Date myDate = null;
if (date != null) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(dateType, amount);
myDate = calendar.getTime();
}
return myDate;
}
/**
* 获取精确的日期
*
* @param timestamps 时间long集合
* @return 日期
*/
private static Date getAccurateDate(List<Long> timestamps) {
Date date = null;
long timestamp = 0;
Map<Long, long[]> map = new HashMap<>();
List<Long> absoluteValues = new ArrayList<>();
if (timestamps != null && !timestamps.isEmpty()) {
if (timestamps.size() > 1) {
for (int i = 0; i < timestamps.size(); i++) {
for (int j = i + 1; j < timestamps.size(); j++) {
long absoluteValue = Math.abs(timestamps.get(i)
- timestamps.get(j));
absoluteValues.add(absoluteValue);
long[] timestampTmp = {timestamps.get(i),
timestamps.get(j)};
map.put(absoluteValue, timestampTmp);
}
}
// 有可能有相等的情况。如2012-11和2012-11-01。时间戳是相等的。此时minAbsoluteValue为0
// 因此不能将minAbsoluteValue取默认值0
long minAbsoluteValue = -1;
if (!absoluteValues.isEmpty()) {
minAbsoluteValue = absoluteValues.get(0);
for (int i = 1; i < absoluteValues.size(); i++) {
if (minAbsoluteValue > absoluteValues.get(i)) {
minAbsoluteValue = absoluteValues.get(i);
}
}
}
if (minAbsoluteValue != -1) {
long[] timestampsLastTmp = map.get(minAbsoluteValue);
long dateOne = timestampsLastTmp[0];
long dateTwo = timestampsLastTmp[1];
if (absoluteValues.size() > 1) {
timestamp = Math.abs(dateOne) > Math.abs(dateTwo) ? dateOne
: dateTwo;
}
}
} else {
timestamp = timestamps.get(0);
}
}
if (timestamp != 0) {
date = new Date(timestamp);
}
return date;
}
/**
* 根据开始时间和结束时间获取间隔的时间(单位/小时)
*
* @param startTime
* @param endTime
* @return
*/
public static Double getIntervalHours(String startTime, String endTime) {
Date staDate = DateUtils.stringToDate(startTime, DateStyle.HH_MM_SS);
Date endDate = DateUtils.stringToDate(endTime, DateStyle.HH_MM_SS);
if(staDate == null || endDate == null) return null;
BigDecimal startTimeStamp = BigDecimal.valueOf(staDate.getTime());
BigDecimal endTimeStamp = BigDecimal.valueOf(endDate.getTime());
BigDecimal hours = endTimeStamp.subtract(startTimeStamp).divide(new BigDecimal(1000 * 60 * 60), 2, BigDecimal.ROUND_DOWN);
return hours.doubleValue();
}
/**
* 判断字符串是否为日期字符串
*
* @param date 日期字符串
* @return true or false
*/
public static boolean isDate(String date) {
boolean isDate = false;
if (date != null && getDateStyle(date) != null) {
isDate = true;
}
return isDate;
}
/**
* 获取日期字符串的日期风格。失敗返回null。
*
* @param date 日期字符串
* @return 日期风格
*/
public static DateStyle getDateStyle(String date) {
DateStyle dateStyle = null;
Map<Long, DateStyle> map = new HashMap<>();
List<Long> timestamps = new ArrayList<>();
for (DateStyle style : DateStyle.values()) {
if (style.isShowOnly()) {
continue;
}
Date dateTmp = null;
if (date != null) {
try {
ParsePosition pos = new ParsePosition(0);
dateTmp = getDateFormat(style.getValue()).parse(date, pos);
if (pos.getIndex() != date.length()) {
dateTmp = null;
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
if (dateTmp != null) {
timestamps.add(dateTmp.getTime());
map.put(dateTmp.getTime(), style);
}
}
Date accurateDate = getAccurateDate(timestamps);
if (accurateDate != null) {
dateStyle = map.get(accurateDate.getTime());
}
return dateStyle;
}
/**
* 将日期字符串转化为日期。失败返回null。
*
* @param date 日期字符串
* @return 日期
*/
public static Date stringToDate(String date) {
DateStyle dateStyle = getDateStyle(date);
return stringToDate(date, dateStyle);
}
/**
* 将日期字符串转化为日期。失败返回null。
*
* @param date 日期字符串
* @param pattern 日期格式
* @return 日期
*/
public static Date stringToDate(String date, String pattern) {
Date myDate = null;
if (date != null) {
try {
myDate = getDateFormat(pattern).parse(date);
} catch (Exception e) {
log.error(e.getMessage());
}
}
return myDate;
}
/**
* 将日期字符串转化为日期。失败返回null。
*
* @param date 日期字符串
* @param dateStyle 日期风格
* @return 日期
*/
public static Date stringToDate(String date, DateStyle dateStyle) {
Date myDate = null;
if (dateStyle != null) {
myDate = stringToDate(date, dateStyle.getValue());
}
return myDate;
}
/**
* 将日期转化为日期字符串。失败返回null。
*
* @param date 日期
* @param pattern 日期格式
* @return 日期字符串
*/
public static String dateToString(Date date, String pattern) {
return getDateFormat(pattern).format(date);
}
/**
* 将日期转化为日期字符串。失败返回null。
*
* @param date 日期
* @param dateStyle 日期风格
* @return 日期字符串
*/
public static String dateToString(Date date, DateStyle dateStyle) {
String dateString = "";
if (dateStyle != null) {
dateString = dateToString(date, dateStyle.getValue());
}
return dateString;
}
/**
* 将日期字符串转化为另一日期字符串。失败返回null。
*
* @param date 旧日期字符串
* @param newPattern 新日期格式
* @return 新日期字符串
*/
public static String stringToString(String date, String newPattern) {
DateStyle oldDateStyle = getDateStyle(date);
return stringToString(date, oldDateStyle, newPattern);
}
/**
* 将日期字符串转化为另一日期字符串。失败返回null。
*
* @param date 旧日期字符串
* @param newDateStyle 新日期风格
* @return 新日期字符串
*/
public static String stringToString(String date, DateStyle newDateStyle) {
DateStyle oldDateStyle = getDateStyle(date);
return stringToString(date, oldDateStyle, newDateStyle);
}
/**
* 将日期字符串转化为另一日期字符串。失败返回null。
*
* @param date 旧日期字符串
* @param olddPattern 旧日期格式
* @param newPattern 新日期格式
* @return 新日期字符串
*/
public static String stringToString(String date, String olddPattern,
String newPattern) {
return dateToString(stringToDate(date, olddPattern), newPattern);
}
/**
* 将日期字符串转化为另一日期字符串。失败返回null。
*
* @param date 旧日期字符串
* @param olddDteStyle 旧日期风格
* @param newParttern 新日期格式
* @return 新日期字符串
*/
public static String stringToString(String date, DateStyle olddDteStyle,
String newParttern) {
String dateString = null;
if (olddDteStyle != null) {
dateString = stringToString(date, olddDteStyle.getValue(),
newParttern);
}
return dateString;
}
/**
* 将日期字符串转化为另一日期字符串。失败返回null。
*
* @param date 旧日期字符串
* @param olddPattern 旧日期格式
* @param newDateStyle 新日期风格
* @return 新日期字符串
*/
public static String stringToString(String date, String olddPattern,
DateStyle newDateStyle) {
String dateString = null;
if (newDateStyle != null) {
dateString = stringToString(date, olddPattern,
newDateStyle.getValue());
}
return dateString;
}
/**
* 将日期字符串转化为另一日期字符串。失败返回null。
*
* @param date 旧日期字符串
* @param olddDteStyle 旧日期风格
* @param newDateStyle 新日期风格
* @return 新日期字符串
*/
public static String stringToString(String date, DateStyle olddDteStyle,
DateStyle newDateStyle) {
String dateString = null;
if (olddDteStyle != null && newDateStyle != null) {
dateString = stringToString(date, olddDteStyle.getValue(),
newDateStyle.getValue());
}
return dateString;
}
/**
* 格式化时间
*
* @param date
* @param dateStyle
* @return 时间
*/
public static Date dateForMat(Date date, DateStyle dateStyle) {
return stringToDate(dateToString(date, dateStyle), dateStyle);
}
/**
* 增加日期的年份。失败返回null。
*
* @param date 日期
* @param yearAmount 增加数量。可为负数
* @return 增加年份后的日期字符串
*/
public static String addYear(String date, int yearAmount) {
return addInteger(date, Calendar.YEAR, yearAmount);
}
/**
* 增加日期的值。失败返回null。
*
* @param date 日期
* @param type 添加的类型 年、月、日、时、分、秒
* @param amount 增加数量
* @return
*/
public static Date add(Date date, int type, int amount) {
return addInteger(date, type, amount);
}
/**
* 增加日期的年份。失败返回null。
*
* @param date 日期
* @param yearAmount 增加数量。可为负数
* @return 增加年份后的日期
*/
public static Date addYear(Date date, int yearAmount) {
return addInteger(date, Calendar.YEAR, yearAmount);
}
/**
* 增加日期的月份。失败返回null。
*
* @param date 日期
* @param monthAmount 增加数量。可为负数
* @return 增加月份后的日期字符串
*/
public static String addMonth(String date, int monthAmount) {
return addInteger(date, Calendar.MONTH, monthAmount);
}
/**
* 增加日期的月份。失败返回null。
*
* @param date 日期
* @param monthAmount 增加数量。可为负数
* @return 增加月份后的日期
*/
public static Date addMonth(Date date, int monthAmount) {
return addInteger(date, Calendar.MONTH, monthAmount);
}
/**
* 增加日期的天数。失败返回null。
*
* @param date 日期字符串
* @param dayAmount 增加数量。可为负数
* @return 增加天数后的日期字符串
*/
public static String addDay(String date, int dayAmount) {
return addInteger(date, Calendar.DATE, dayAmount);
}
/**
* 增加日期的天数。失败返回null。
*
* @param date 日期
* @param dayAmount 增加数量。可为负数
* @return 增加天数后的日期
*/
public static Date addDay(Date date, int dayAmount) {
return addInteger(date, Calendar.DATE, dayAmount);
}
/**
* 增加日期的小时。失败返回null。
*
* @param date 日期字符串
* @param hourAmount 增加数量。可为负数
* @return 增加小时后的日期字符串
*/
public static String addHour(String date, int hourAmount) {
return addInteger(date, Calendar.HOUR_OF_DAY, hourAmount);
}
/**
* 增加日期的小时。失败返回null。
*
* @param date 日期
* @param hourAmount 增加数量。可为负数
* @return 增加小时后的日期
*/
public static Date addHour(Date date, int hourAmount) {
return addInteger(date, Calendar.HOUR_OF_DAY, hourAmount);
}
/**
* 增加日期的分钟。失败返回null。
*
* @param date 日期字符串
* @param minuteAmount 增加数量。可为负数
* @return 增加分钟后的日期字符串
*/
public static String addMinute(String date, int minuteAmount) {
return addInteger(date, Calendar.MINUTE, minuteAmount);
}
/**
* 增加日期的分钟。失败返回null。
*
* @param date 日期
* @param minuteAmount 增加数量。可为负数
* @return 增加分钟后的日期
*/
public static Date addMinute(Date date, int minuteAmount) {
return addInteger(date, Calendar.MINUTE, minuteAmount);
}
/**
* 增加日期的秒钟。失败返回null。
*
* @param date 日期字符串
* @param secondAmount 增加数量。可为负数
* @return 增加秒钟后的日期字符串
*/
public static String addSecond(String date, int secondAmount) {
return addInteger(date, Calendar.SECOND, secondAmount);
}
/**
* 增加日期的秒钟。失败返回null。
*
* @param date 日期
* @param secondAmount 增加数量。可为负数
* @return 增加秒钟后的日期
*/
public static Date addSecond(Date date, int secondAmount) {
return addInteger(date, Calendar.SECOND, secondAmount);
}
/**
* 获取日期的年份。失败返回0。
*
* @param date 日期字符串
* @return 年份
*/
public static int getYear(String date) {
return getYear(stringToDate(date));
}
/**
* 获取日期的年份。失败返回0。
*
* @param date 日期
* @return 年份
*/
public static int getYear(Date date) {
return getInteger(date, Calendar.YEAR);
}
/**
* 获取日期的月份。失败返回0。
*
* @param date 日期字符串
* @return 月份
*/
public static int getMonth(String date) {
return getMonth(stringToDate(date));
}
/**
* 获取日期的月份。失败返回0。
*
* @param date 日期
* @return 月份
*/
public static int getMonth(Date date) {
return getInteger(date, Calendar.MONTH) + 1;
}
/**
* 获取日期的星期。失败返回0
*
* @param date 日期
* @return 星期
*/
public static int getWeek(String date) {
return getWeek(stringToDate(date));
}
/**
* 获取日期的星期。失败返回0
*
* @param date 日期
* @return 星期
*/
public static int getWeek(Date date) {
return getInteger(date, Calendar.DAY_OF_WEEK) - 1;
}
/**
* 获取日期的天数。失败返回0。
*
* @param date 日期字符串
* @return 天
*/
public static int getDay(String date) {
return getDay(stringToDate(date));
}
/**
* 获取日期的天数。失败返回0。
*
* @param date 日期
* @return 天
*/
public static int getDay(Date date) {
return getInteger(date, Calendar.DATE);
}
/**
* 获取日期的小时。失败返回0。
*
* @param date 日期字符串
* @return 小时
*/
public static int getHour(String date) {
return getHour(stringToDate(date));
}
/**
* 获取日期的小时。失败返回0。
*
* @param date 日期
* @return 小时
*/
public static int getHour(Date date) {
return getInteger(date, Calendar.HOUR_OF_DAY);
}
/**
* 获取日期的分钟。失败返回0。
*
* @param date 日期字符串
* @return 分钟
*/
public static int getMinute(String date) {
return getMinute(stringToDate(date));
}
/**
* 获取日期的分钟。失败返回0。
*
* @param date 日期
* @return 分钟
*/
public static int getMinute(Date date) {
return getInteger(date, Calendar.MINUTE);
}
/**
* 获取日期的秒钟。失败返回0。
*
* @param date 日期字符串
* @return 秒钟
*/
public static int getSecond(String date) {
return getSecond(stringToDate(date));
}
/**
* 获取日期的秒钟。失败返回0。
*
* @param date 日期
* @return 秒钟
*/
public static int getSecond(Date date) {
return getInteger(date, Calendar.SECOND);
}
/**
* 获取日期 。默认yyyy-MM-dd格式。失败返回null。
*
* @param date 日期字符串
* @return 日期
*/
public static String getDate(String date) {
return stringToString(date, DateStyle.YYYY_MM_DD);
}
/**
* 获取日期。默认yyyy-MM-dd格式。失败返回null。
*
* @param date 日期
* @return 日期
*/
public static String getDate(Date date) {
return dateToString(date, DateStyle.YYYY_MM_DD);
}
/**
* 获取日期的时间。默认HH:mm:ss格式。失败返回null。
*
* @param date 日期字符串
* @return 时间
*/
public static String getTime(String date) {
return stringToString(date, DateStyle.HH_MM_SS);
}
/**
* 获取日期的时间。默认HH:mm:ss格式。失败返回null。
*
* @param date 日期
* @return 时间
*/
public static String getTime(Date date) {
return dateToString(date, DateStyle.HH_MM_SS);
}
/**
* 获取两个日期相差的天数
*
* @param date 日期字符串
* @param otherDate 另一个日期字符串
* @return 相差天数。如果失败则返回-1
*/
public static int getIntervalDays(String date, String otherDate) {
return getIntervalDays(stringToDate(date), stringToDate(otherDate));
}
/**
* @param date 日期
* @param otherDate 另一个日期
* @return 相差天数。如果失败则返回-1
*/
public static int getIntervalDays(Date date, Date otherDate) {
int num = -1;
Date dateTmp = DateUtils.stringToDate(DateUtils.getDate(date),
DateStyle.YYYY_MM_DD);
Date otherDateTmp = DateUtils.stringToDate(DateUtils.getDate(otherDate),
DateStyle.YYYY_MM_DD);
if (dateTmp != null && otherDateTmp != null) {
long time = Math.abs(dateTmp.getTime() - otherDateTmp.getTime());
num = (int) (time / (24 * 60 * 60 * 1000));
}
return num;
}
/**
* @param date 日期
* @param otherDate 另一个日期
* @return 相差分钟数。如果失败则返回-1
*/
public static int getIntervalMinute(Date date, Date otherDate) {
int num = -1;
if (date != null && otherDate != null) {
long time = Math.abs(date.getTime() - otherDate.getTime());
num = (int) (time / (1000 * 60));
}
return num;
}
/**
* Description :获取当前时间yyyyMMddHHmmss字符串
*
* @return String 当前时间yyyyMMddHHmmss字符串
*/
public static String getSecondString() {
return dateToString(new Date(), DateStyle.YYYYMMDDHHMMSS);
}
/**
* Description : 获取当前时间yyyyMMddHHmmssSSS字符串
*
* @return String 当前时间yyyyMMddHHmmssSSS字符串
*/
public static String getMillisecondString() {
return dateToString(new Date(), DateStyle.YYYYMMDDHHMMSSSSS);
}
/**
* 比较两个日期的大小
*
* @param date1 日期1
* @param date2 日期2
* @return 1 date1 > date2; -1 date1 < date2 ; 0 date1 = date2
*/
public static int compareDate(String date1, String date2) {
Date dt1 = stringToDate(date1);
Date dt2 = stringToDate(date2);
return compareDate(dt1, dt2);
}
/**
* 比较两个日期的大小
*
* @param date1 日期1
* @param date2 日期2
* @return 1 date1 > date2; -1 date1 < date2 ; 0 date1 = date2
*/
public static int compareDate(Date date1, Date date2) {
if(date1 == null || date2 == null) return 0;
if (date1.getTime() > date2.getTime()) {
return 1;
} else if (date1.getTime() < date2.getTime()) {
return -1;
} else {
return 0;
}
}
/**
* Description:[判断两个日期是否相等]
*
* @param d1 日期1
* @param d2 日期2
* @return boolean 相等true
* <p>
* Created on 2019/4/17
* @author: yinguijin
*/
public static boolean isSameDate(Date d1, Date d2) {
if (null == d1 || null == d2)
return false;
Calendar cal1 = Calendar.getInstance();
cal1.setTime(d1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(d2);
return cal1.get(0) == cal2.get(0) && cal1.get(1) == cal2.get(1) && cal1.get(6) == cal2.get(6);
}
/**
* Description:[获取两个时间的时间差]
*
* @param date1 时间一
* @param date2 时间二
* @param type 获取的类型 天 时 分 秒
* @return 时间一 减 时间二 的值
* <p>
* Created on 2019/4/17
* @author: yinguijin
*/
public static int dayDiff(Date date1, Date date2, int type) {
long diff = date1.getTime() - date2.getTime();
int nd = 1000 * 24 * 60 * 60;
int nh = 1000 * 60 * 60;
int nm = 1000 * 60;
int ns = 1000;
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff / nh;
// 计算差多少分钟
long min = diff / nm;
// 计算差多少秒
long sec = diff / ns;
if (Calendar.DATE == type) {
return (int) day;
} else if (Calendar.HOUR_OF_DAY == type) {
return (int) hour;
} else if (Calendar.MINUTE == type) {
return (int) min;
} else if (Calendar.SECOND == type) {
return (int) sec;
} else {
return (int) diff;
}
}
/**
* Description:[根据参数时间获取前推的整点时间:列2017-11-22 17:13返回17:00;列2017-11-22 17:59返回17:30]
*
* @param date 时间
* @return 列2017-11-22 17:13返回17:00;列2017-11-22 17:59返回17:30
* <p>
* Created on 2019/4/17
* @author: yinguijin
*/
public static Date wholeHour(Date date) {
int hour = DateUtils.getHour(date);
int minute = DateUtils.getMinute(date);
if (minute >= 30) {
minute = 30;
} else {
minute = 00;
}
String endTime = hour + ":" + minute;
return DateUtils.stringToDate(endTime, DateStyle.HH_MM);
}
/**
* <p>Description:[计算两个日期相差的月数,不足15天按照半个月计算,超过15天按照一个月计算]</p>
*
* @param startDate 开始时间
* @param endDate 结束时间
* @return 相差的月数0.5的倍数
* Created on 2019/4/17
* @author: yinguijin
*/
public static double getMonths(Date startDate, Date endDate) {
int startYear = DateUtils.getYear(startDate);
int endYear = DateUtils.getYear(endDate);
int startMonth = DateUtils.getMonth(startDate);
int endMonth = DateUtils.getMonth(endDate);
int startDay = DateUtils.getDay(startDate);
int endDay = DateUtils.getDay(endDate);
int endLastDay = DateUtils.getLastDay(endDate);
int startLastDay = DateUtils.getLastDay(startDate);
int intervalYears = endYear - startYear;
double intervalMonths;
int intervalDays;
if (intervalYears >= 1) {
intervalDays = (startLastDay - startDay) + endDay + 1;
intervalMonths = (12.0 - startMonth) + endMonth + 1;
if (startDay == 1 && endDay == endLastDay) {
intervalDays = 0;
} else {
if (startDay != 1) {
intervalMonths -= 1.0;
} else {
intervalDays = endDay;
}
if (endDay != endLastDay) {
intervalMonths -= 1.0;
} else {
intervalDays = startLastDay - startDay + 1;
}
}
} else {
intervalMonths = endMonth - startMonth + 1.0;
if (intervalMonths > 1.0) {
intervalDays = (startLastDay - startDay) + endDay + 1;
if (startDay == 1 && endDay == endLastDay) {
intervalDays = 0;
} else {
if (startDay != 1) {
intervalMonths -= 1.0;
} else {
intervalDays = endDay;
}
if (endDay != endLastDay) {
intervalMonths -= 1.0;
} else {
intervalDays = startLastDay - startDay + 1;
}
}
intervalMonths = intervalMonths < 0.0 ? 0.0 : intervalMonths;
} else {
intervalMonths = 0.0;
intervalDays = endDay - startDay + 1;
}
}
if (intervalDays == 0) {
intervalMonths += 0.0;
} else if (intervalDays <= 15) {
intervalMonths += 0.5;
} else if (intervalDays >= 31) {
intervalMonths += 1.0;
if (intervalDays - 31 > 15) {
intervalMonths += 1.0;
} else if (intervalDays - 31 >= 1) {
intervalMonths += 0.5;
}
} else {
intervalMonths += 1.0;
}
for (int i = 1; i < intervalYears; i++) {
intervalMonths += 12.0;
}
return intervalMonths;
}
/**
* <p>Description:[计算当前时间所处的拆分时间段]</p>
*
* @return 拆分时间段Integer值
* Created on 2019/4/17
* @author: yinguijin
*/
public static Integer getSplitTimeByNow() {
return getSplitTime(new Date());
}
/**
* <p>Description:[计算时间所处的拆分时间段]</p>
*
* @return 拆分时间段Integer值
* Created on 2019/4/17
* @author: yinguijin
*/
public static Integer getSplitTime(Date date) {
int hour = DateUtils.getHour(date);
int minute = DateUtils.getMinute(date);
if (minute > 0 && minute < 30) {
minute = 30;
}
int splitTime = hour * 2 + 1;
if (minute >= 30) {
splitTime += 1;
}
return splitTime;
}
/**
* Description:[获取当前月的第一天的日期]
*
* @return 当前月第一天
* <p>
* Created on 2019/4/17
* @author: yinguijin
*/
public static Date getfirstDate() {
Calendar c = Calendar.getInstance();
c.add(Calendar.MONTH, 0);
c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
return stringToDate(getDateFormat(DateStyle.YYYY_MM_DD.getValue()).format(c.getTime()));
}
/**
* Description:[获取当前月的最后一天的日期]
*
* @return 当前月的最后一天
* <p>
* Created on 2019/4/17
* @author: yinguijin
*/
public static Date getlastDate() {
Calendar c = Calendar.getInstance();
c.add(Calendar.MONTH, 0);
c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
return stringToDate(getDateFormat(DateStyle.YYYY_MM_DD.getValue()).format(c.getTime()));
}
/**
* Description:[获取指定月的最后一天的日期]
*
* @return 指定的最后一天
* <p>
* Created on 2019/4/17
* @author: yinguijin
*/
public static int getLastDay(Date date) {
Calendar c = Calendar.getInstance();
c.setTime(date);
return c.getActualMaximum(Calendar.DAY_OF_MONTH);
}
/**
* Description:[获取指定月的第一天的日期]
*
* @return 指定的第一天
* <p>
* Created on 2019/4/17
* @author: yinguijin
*/
public static int getFirstDay(Date date) {
Calendar c = Calendar.getInstance();
c.setTime(date);
return c.getActualMinimum(Calendar.DAY_OF_MONTH);
}
/**
* <p>Description:[获取当前日期字符串]</p>
* Created on 2019/4/17
*
* @author: yinguijin
*/
public static String getCurrentDateString() {
return dateToString(new Date(), DateStyle.YYYY_MM_DD);
}
/**
* <p>Description:[获取当前日期]</p>
* Created on 2019/4/17
*
* @author: yinguijin
*/
public static Date getCurrentDate() {
return stringToDate(getCurrentDateString(), DateStyle.YYYY_MM_DD);
}
/**
* <p>Description:[获取某月最大日期]</p>
* Created on 2019/4/17
*
* @author: yinguijin
*/
public static int getMonthMaxDay(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.set(getYear(date), getMonth(date) - 1, 1);
return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
}
/**
* <p>Discription:[根据传入的两个时间计算相差几个小时,结果保留一位小数]</p>
*
* @param dateLast date类型的时间1
* @param dateNext date类型的时间2
* @return Double 返回保留一位小数的绝对值
* Created on 2019/4/17
* @author: yinguijin
*/
public static Double calculateHour(Date dateLast, Date dateNext) {
long millisLast = dateLast.getTime();
long millisNext = dateNext.getTime();
double differenceMillis = (double) (millisNext - millisLast);
double hourDouble = differenceMillis / 1000 / 60 / 60;
hourDouble = BigDecimal.valueOf(hourDouble).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
return Math.abs(hourDouble);
}
/**
* 判断一个时间是否在一个时间段之间
*
* @param date 为目标时间
* @param startDate 为起始时间
* @param endDate 为结束时间
* @return true or false
* Created on 2019/4/17
* @author: yinguijin
*/
public static boolean getInDate(String date, String startDate, String endDate) {
boolean flag = false;
Date targetTime = DateUtils.stringToDate(date, DateStyle.HH_MM);
Date startTime = DateUtils.stringToDate(startDate, DateStyle.HH_MM);
Date endTime;
if (endDate.equals("24:00")) {
endTime = addDay(DateUtils.stringToDate("00:00", DateStyle.HH_MM), 1);
} else {
endTime = DateUtils.stringToDate(endDate, DateStyle.HH_MM);
}
//目标时间大于等于开始时间 且 目标时间小于结束时间 时返回true
if (targetTime != null && targetTime.compareTo(startTime) >= 0 && targetTime.compareTo(endTime) < 0) {
flag = true;
}
return flag;
}
/**
* @param startTime 开始时间
* @param endTime 结束时间
* @return java.lang.String 时段名称
* @description: 获取时段名称
* @author yinguijin
* @date 2019/5/5 20:12
*/
public static String getSectimeName(String startTime, String endTime) {
String secname = "平峰";
String st = startTime.split(":")[0];
String et = endTime.split(":")[0];
if (StringUtils.isEmpty(st) || StringUtils.isEmpty(et)) {
return secname;
}
int s = Integer.parseInt(st);
int e = Integer.parseInt(et);
if (s >= 0 && e <= 6) {
secname = "低峰";
} else if (s >= 6 && e <= 7) {
secname = "早平峰";
} else if (s >= 7 && e <= 9) {
secname = "早高峰";
} else if (s >= 9 && e <= 12) {
secname = "平峰";
} else if (s >= 12 && e <= 14) {
secname = "次平峰";
} else if (s >= 14 && e <= 17) {
secname = "平峰";
} else if (s >= 17 && e <= 19) {
secname = "晚高峰";
} else if (s >= 19 && e <= 22) {
secname = "次平峰";
} else if (s >= 22 && e <= 24) {
secname = "低峰";
}
return secname;
}
/**
* @param cntDateBeg 开始时间
* @param cntDateEnd 结束时间
* @return
*/
public static List<String> addDates(String cntDateBeg, String cntDateEnd) {
List<String> list = new ArrayList<>();
//拆分成数组
String[] dateBegs = cntDateBeg.split("-");
String[] dateEnds = cntDateEnd.split("-");
//开始时间转换成时间戳
Calendar start = Calendar.getInstance();
start.set(Integer.valueOf(dateBegs[0]), Integer.valueOf(dateBegs[1]) - 1, Integer.valueOf(dateBegs[2]));
Long startTIme = start.getTimeInMillis();
//结束时间转换成时间戳
Calendar end = Calendar.getInstance();
end.set(Integer.valueOf(dateEnds[0]), Integer.valueOf(dateEnds[1]) - 1, Integer.valueOf(dateEnds[2]));
Long endTime = end.getTimeInMillis();
//定义一个一天的时间戳时长
Long oneDay = 1000 * 60 * 60 * 24l;
Long time = startTIme;
//循环得出
while (time <= endTime) {
list.add(new SimpleDateFormat("yyyy-MM-dd").format(new Date(time)));
time += oneDay;
}
return list;
}
}
\ No newline at end of file
package net.wanji.datacenter.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
public FastJson2JsonRedisSerializer(Class<T> clazz) {
super(); this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return (T) JSON.parseObject(str, clazz);
}
}
\ No newline at end of file
package net.wanji.datacenter.util;
import net.wanji.datacenter.constant.Constant;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @description: redis工具类
* @author wanji
* @version 1.0
* Created on 2019/4/29 20:34
*/
@Component
public class RedisUtils {
/**
* 注入redisTemplate
*/
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* @description: 判断是否存在Key
* @param key redis的Key
* @return boolean true:有 false:无
*/
public boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* @description: 添加字符串
* @param key redis的Key
* @param value 添加redis的value
*/
public void set(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* @description: 添加对象
* @param key redis的Key
* @param object 添加redis的value
*/
public void set(String key, Object object) {
redisTemplate.opsForValue().set(key, object);
}
/**
* @description: 添加带生命周期的对象
* @param key redis的Key
* @param object 添加redis的value
* @param seconds 失效时间
*/
public void setAndExpire(String key, Object object, int seconds) {
redisTemplate.opsForValue().set(key, object);
redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
}
/**
* @description: 添加带生命周期的对象
* @param key redis的Key
* @param value 添加redis的value
* @param seconds 失效时间
*/
public void setAndExpire(String key, String value, int seconds) {
redisTemplate.opsForValue().set(key, value);
redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
}
/**
* @description: 获取对象
* @param key redis的Key
* @return Object 返回对象
*/
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* @description: 存入redis的hash
* @param key redis的Key
* @param field 字段值
* @param value 存入的值
*/
public void setHash(String key, String field, String value) {
redisTemplate.opsForHash().put(key, field, value);
}
/**
* @description: 存入redis的hash
* @param key redis的Key
* @param field 字段值
* @param value 存入的值
*/
public void setHash(String key, String field, Object value) {
redisTemplate.opsForHash().put(key, field, value);
}
/**
* @description: 根据key和字段值获取内容值
* @param key redis的Key
* @param field 字段值
* @return String 返回字符串
*/
public String getHash(String key, String field) {
return (String)redisTemplate.opsForHash().get(key, field);
}
/**
* @description: 根据field删除值
* @param key redis的Key
* @param field 字段值
*/
public void delHashMap(String key, String field) {
redisTemplate.boundHashOps(key).delete(field);
}
/**
* @description: 存入hash集合
* @param key redis的Key
* @param hashmap 存入的Map集合
*/
public void setHashMap(String key, Map<String, Object> hashmap){
redisTemplate.opsForHash().putAll(key, hashmap);
}
/**
* @description: 取出hash集合
* @param key redis的Key
* @return Map<Object, Object> 返回Map集合
*/
public Map<Object, Object> getHashMap(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* @description: 存入redis的Set
* @param key redis的Key
* @param object 对象
*/
public void setSet(String key,Object object){
redisTemplate.opsForSet().add(key, object);
}
/**
* @description: 获取redis的Set
* @param key redis的Key
* @return Set<Object> Set集合
*/
public Set<Object> getSet(String key){
return redisTemplate.opsForSet().members(key);
}
/**
* @discription: 查看值是否是set成员
* @param key set的key
* @param value set的成员
* @return 是否是set成员
*/
public Boolean isSetMember(String key, Object value) {
return redisTemplate.opsForSet().isMember(key, value);
}
/**
* @description:设置key的过期时间,endTime格式:yyyy-MM-dd hh:mm:ss
* @param key redis的Key
* @param endTime 结束时间
*/
public void setExpire(String key, Date endTime) {
long seconds = endTime.getTime() - System.currentTimeMillis();
redisTemplate.expire(key, (int) (seconds / 1000), TimeUnit.SECONDS);
}
/**
* @description: 设置key的过期时间
* @param key redis的Key
* @param time 过期时间(秒)
*/
public void setExpire(String key, int time) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
/**
* <p>Discription:获取key的过期时间
* @param key redis的Key
* @return 过期时间(秒)
*/
public Long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* @description: 在redis消息队列队尾插入数据
* @param key redis的Key
* @param object 添加的对象
*/
public void tailPush(String key, Object object){
redisTemplate.opsForList().rightPush(key, object);
}
/**
* @description: 在redis消息队列对头插入数据
* @param key redis的Key
* @param object 添加的对象
*/
public void headPush(String key,Object object){
redisTemplate.opsForList().leftPush(key, object);
}
/**
* @description: 在redis消息队列队尾删除数据
* @param key redis的Key
* @return Object 删除的对象
*/
public Object tailPop(String key){
return redisTemplate.opsForList().rightPop(key);
}
/**
* @description: 在redis消息队列队头删除数据
* @param key redis的Key
* @return Object 删除的对象
*/
public Object headPop(String key){
return redisTemplate.opsForList().leftPop(key);
}
/**
* @description: 删除redis的值
* @param key redis的Key
*/
public void del(String key) {
if (hasKey(key)) {
redisTemplate.delete(key);
}
}
/**
* @description: 清理redis缓存
*/
public void flushDB(){
redisTemplate.getConnectionFactory().getConnection().flushDb();
}
/**
* @description: 根据类型生成版本号
* @param type 类型key区分
* @return 版本号
* @author wanji
* @date 2019/5/5 19:26
*/
public String getVersion(String type) {
String formatDate = DateUtils.dateToString(new Date(), DateStyle.YYYYMMDD);
String key = Constant.KEY_PREFIX + type + formatDate;
//当前时间到第二天还剩多少时间
Date newDate = DateUtils.dateForMat(DateUtils.addDay(new Date(), 1), DateStyle.YYYY_MM_DD);
int liveTime = DateUtils.dayDiff(newDate, new Date(), Calendar.MILLISECOND);
//获取自增号
Long incr = getIncr(key, liveTime);
if(incr == 0) {
incr = getIncr(key, liveTime);//从001开始
}
DecimalFormat df = new DecimalFormat("000");//三位序列号
return formatDate + Constant.SEPARATOR_MINUS + df.format(incr);
}
/**
* 自增ID
* @param key 建
* @param liveTime 过期时间
* @return 自增结果
*/
public Long getIncr(String key, long liveTime) {
RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
Long increment = entityIdCounter.getAndIncrement();
if ((null == increment || increment.longValue() == 0) && liveTime > 0) {//初始设置过期时间
entityIdCounter.expire(liveTime, TimeUnit.MILLISECONDS);//单位毫秒
}
return increment;
}
/**
* 获取全部Redis的key
* @return
*/
public Set<String> keys() {
return redisTemplate.keys("*");
}
/**
* 获取全局ID范围
*
* @param key 建
* @param increment ID范围
* @return
*/
public Long getGlobalIdRange(String key, long increment) {
ValueOperations<String, Object> ops = redisTemplate.opsForValue();
Long newIdRangeStart = ops.increment(key, increment);
// The range of IDs that are now reserved are from newIdRangeStart - increment + 1 to newIdRangeStart.
return newIdRangeStart - increment + 1;
}
/**
* 带过期时间存入 zset
* @param ttlInMillis 存活时间毫秒数
*/
public void addToSortedSetWithExpiry(String key, String value, long ttlInMillis) {
long score = new Date().getTime() + ttlInMillis;
redisTemplate.opsForZSet().add(key, value, score);
}
/**
* 删除过期的 zset 元素
*/
public void removeExpiredElements(String key) {
long now = new Date().getTime();
redisTemplate.opsForZSet().removeRangeByScore(key, 0, now);
}
}
...@@ -43,7 +43,7 @@ spring: ...@@ -43,7 +43,7 @@ spring:
max-poll-records: 1 max-poll-records: 1
broker-id: 0 broker-id: 0
auto-commit-interval: 1S auto-commit-interval: 1S
auto-offset-reset: earliest auto-offset-reset: latest
enable-auto-commit: false enable-auto-commit: false
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
...@@ -52,6 +52,18 @@ spring: ...@@ -52,6 +52,18 @@ spring:
concurrency: 3 concurrency: 3
ack-mode: manual_immediate ack-mode: manual_immediate
missing-topics-fatal: false missing-topics-fatal: false
redis:
host: 37.12.182.29
port: 6379
password: Wanji300552
jedis:
pool:
max-active: 200
max-wait: 5000
max-idle: 20
min-idle: 10
timeout: 5000
database: 7
mybatis-plus: mybatis-plus:
mapper-locations: classpath*:mapper/*.xml,classpath:mapper/*/*.xml mapper-locations: classpath*:mapper/*.xml,classpath:mapper/*/*.xml
......
...@@ -11,12 +11,12 @@ import com.wanji.indicators.task.lightstatus.model.VehicleHeadTimeModel; ...@@ -11,12 +11,12 @@ import com.wanji.indicators.task.lightstatus.model.VehicleHeadTimeModel;
import com.wanji.indicators.task.trajectory.pojo.CrossEventResult; import com.wanji.indicators.task.trajectory.pojo.CrossEventResult;
import com.wanji.indicators.task.trajectory.pojo.StartDuration; import com.wanji.indicators.task.trajectory.pojo.StartDuration;
import com.wanji.indicators.util.GeomsConvertUtil; import com.wanji.indicators.util.GeomsConvertUtil;
import com.wanji.indicators.util.PtInPolyUtil;
import org.apache.flink.api.common.state.MapState; import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor; import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.configuration.Configuration; import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction; import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector; import org.apache.flink.util.Collector;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.Instant; import java.time.Instant;
...@@ -32,14 +32,16 @@ import java.util.stream.StreamSupport; ...@@ -32,14 +32,16 @@ import java.util.stream.StreamSupport;
* @Description : * @Description :
*/ */
public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, CrossFrameModel, CrossEventResult> { public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, CrossFrameModel, CrossEventResult> {
//车道上离停止线最近的车辆缓存 // 车道上离停止线最近的车辆缓存。Key:方向-车道ID
private transient MapState<String, CarTrackModel> mapState; private transient MapState<String, CarTrackModel> mapState;
//绿灯总时长 // 绿灯总时长。Key:路口ID-方向
private transient MapState<String, Integer> greenTotalTimeState; private transient MapState<String, Integer> greenTotalTimeState;
//车道车头时距缓存 // 车道车头时距缓存。Key:方向-车道ID
private transient MapState<String, VehicleHeadTimeModel> resultState; private transient MapState<String, VehicleHeadTimeModel> resultState;
// 开始时间和持续时长状态。Key:方向 // 开始时间和持续时长状态。Key:方向
private transient MapState<Integer, StartDuration> dirState; private transient MapState<Integer, StartDuration> dirState;
// 方向最近一次灯色。Key:方向,Value:灯色
private transient MapState<Integer, String> dirLastSecondState;
@Override @Override
public void open(Configuration parameters) { public void open(Configuration parameters) {
...@@ -47,6 +49,7 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -47,6 +49,7 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
resultState = getRuntimeContext().getMapState(new MapStateDescriptor<>("light_result_map", String.class, VehicleHeadTimeModel.class)); resultState = getRuntimeContext().getMapState(new MapStateDescriptor<>("light_result_map", String.class, VehicleHeadTimeModel.class));
greenTotalTimeState = getRuntimeContext().getMapState(new MapStateDescriptor<>("light_total_time_map", String.class, Integer.class)); greenTotalTimeState = getRuntimeContext().getMapState(new MapStateDescriptor<>("light_total_time_map", String.class, Integer.class));
dirState = getRuntimeContext().getMapState(new MapStateDescriptor<>("dir_map", Integer.class, StartDuration.class)); dirState = getRuntimeContext().getMapState(new MapStateDescriptor<>("dir_map", Integer.class, StartDuration.class));
dirLastSecondState = getRuntimeContext().getMapState(new MapStateDescriptor<>("dir_last_minute", Integer.class, String.class));
} }
@Override @Override
...@@ -55,23 +58,26 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -55,23 +58,26 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
List<CarTrackModel> trackList = value.getTrackList(); List<CarTrackModel> trackList = value.getTrackList();
//灯态数据 //灯态数据
List<CrossRidTurnLampStatusModel> ridLightStatusList = value.getRidTurnLampList(); List<CrossRidTurnLampStatusModel> ridLightStatusList = value.getRidTurnLampList();
//当前南北绿灯放行进口车道 // 当前南北绿灯放行进口车道
Map<Integer, List<CrossRidTurnLampStatusModel>> groupLightStatus = Map<Integer, List<CrossRidTurnLampStatusModel>> groupLightStatus =
ridLightStatusList.stream() ridLightStatusList.stream()
.filter(o -> Objects.nonNull(o) && !StringUtils.isEmpty(o.getLampState()) && o.getLampState().trim().equals(LightStatusEnum.GREEN.getType())) .filter(o -> Objects.nonNull(o) && !StringUtils.isEmpty(o.getLampState())
.filter(o -> o.getDir() == 1 || o.getDir() == 4 || o.getDir() == 5)//非协调方向 && o.getLampState().trim().equals(LightStatusEnum.GREEN.getType()))
.filter(o -> o.getDir() == 1 || o.getDir() == 4 || o.getDir() == 5) // 非协调方向
.filter(o -> !o.getTurn().equals(Constant.PEDESTRAIN_LIGHT_CODE)) // 非行人灯 .filter(o -> !o.getTurn().equals(Constant.PEDESTRAIN_LIGHT_CODE)) // 非行人灯
.filter(o -> !o.getTurn().equals(Constant.RIGHT_LIGHT_CODE)) // 非右转灯 .filter(o -> !o.getTurn().equals(Constant.RIGHT_LIGHT_CODE)) // 非右转灯
.collect(Collectors.groupingBy(CrossRidTurnLampStatusModel::getDir)); .collect(Collectors.groupingBy(CrossRidTurnLampStatusModel::getDir));
//存储当前非协调方向绿灯结束的路口和绿灯时长 // 存储当前非协调方向绿灯结束的路口和绿灯时长
Map<Integer, Integer> expiredGreenLightMap = new HashMap<>(); Map<Integer, Integer> expiredGreenLightMap = new HashMap<>();
if(!greenTotalTimeState.isEmpty()){ if (!greenTotalTimeState.isEmpty()) {
Iterable<String> keys = greenTotalTimeState.keys(); Iterable<String> keys = greenTotalTimeState.keys();
for(String key: keys){ for (String key : keys) {
String[] split = key.trim().split("-"); // "路口ID-方向" String[] split = key.trim().split("-"); // "路口ID-方向"
int dir = Integer.parseInt(split[1]); int dir = Integer.parseInt(split[1]);
if(!groupLightStatus.containsKey(dir)){ String dirLastSecond = dirLastSecondState.get(dir);
if (!groupLightStatus.containsKey(dir)
&& Objects.equals(dirLastSecond, LightStatusEnum.GREEN.getType())) {
expiredGreenLightMap.put(dir, greenTotalTimeState.get(key)); expiredGreenLightMap.put(dir, greenTotalTimeState.get(key));
} }
} }
...@@ -83,20 +89,21 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -83,20 +89,21 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
// 更新绿灯相位周期总时长 // 更新绿灯相位周期总时长
String combinedKey = crossId + "-" + dir; String combinedKey = crossId + "-" + dir;
if(!greenTotalTimeState.contains(combinedKey)){ if (!greenTotalTimeState.contains(combinedKey)) {
greenTotalTimeState.put(combinedKey, value1.get(0).getCyclePhaseCountDown()); greenTotalTimeState.put(combinedKey, value1.get(0).getCyclePhaseCountDown());
} }
//绿灯放行进入路口内的车辆 // 绿灯放行进入路口内的车辆
List<CarTrackModel> runList = trackList.stream() List<CarTrackModel> runList = trackList.stream()
.filter(o -> entry.getKey().equals(o.getRoadnet().getRidDir8()) && o.getRoadnet().getInCrossFlag() == Constant.CROSSING) .filter(o -> entry.getKey().equals(o.getRoadnet().getRidDir8()) && o.getRoadnet().getInCrossFlag() == Constant.CROSSING)
.collect(Collectors.toList()); .collect(Collectors.toList());
if (!runList.isEmpty()) { if (!runList.isEmpty()) {
//按车道分组 // 按车道分组
Map<String, List<CarTrackModel>> groupByLane = runList.stream().collect(Collectors.groupingBy(O -> O.getRoadnet().getLaneId())); Map<String, List<CarTrackModel>> groupByLane = runList.stream()
for (Map.Entry<String, List<CarTrackModel>> entry1 : groupByLane.entrySet()) { .collect(Collectors.groupingBy(O -> O.getRoadnet().getLaneId()));
for (Map.Entry<String, List<CarTrackModel>> entry1 : groupByLane.entrySet()) {
List<CarTrackModel> laneCarList = entry1.getValue(); List<CarTrackModel> laneCarList = entry1.getValue();
// 计算路口内车辆到停止线距离 // 计算路口内车辆到停止线距离
laneCarList.forEach(o -> { laneCarList.forEach(o -> {
...@@ -107,10 +114,11 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -107,10 +114,11 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
double stopLineDist = GeomsConvertUtil.getDistance(o.getLongitude(), o.getLatitude(), Double.parseDouble(sps[0]), Double.parseDouble(sps[1])); double stopLineDist = GeomsConvertUtil.getDistance(o.getLongitude(), o.getLatitude(), Double.parseDouble(sps[0]), Double.parseDouble(sps[1]));
o.setStopLineDist(stopLineDist); o.setStopLineDist(stopLineDist);
} }
}); });
//按距离排序 //按距离排序
laneCarList = laneCarList.stream().sorted(Comparator.comparing(CarTrackModel::getStopLineDist)).collect(Collectors.toList()); laneCarList = laneCarList.stream()
.sorted(Comparator.comparing(CarTrackModel::getStopLineDist))
.collect(Collectors.toList());
//取靠近停止线的一辆车 //取靠近停止线的一辆车
CarTrackModel lastCar = laneCarList.get(0); CarTrackModel lastCar = laneCarList.get(0);
...@@ -119,30 +127,23 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -119,30 +127,23 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
String key = dir + "-" + laneId; String key = dir + "-" + laneId;
CarTrackModel agoCar = mapState.get(key); CarTrackModel agoCar = mapState.get(key);
//绿灯区间计算 // 绿灯区间计算
if (agoCar != null) { if (agoCar != null) {
Integer trackId = lastCar.getId(); Integer trackId = lastCar.getId();
Integer agoTrackId = agoCar.getId(); Integer agoTrackId = agoCar.getId();
//新的车辆驶出停止线 //新的车辆驶出停止线
if (!Objects.equals(agoTrackId, trackId)) { if (!Objects.equals(agoTrackId, trackId)) {
//车辆类型
Integer lastCarType = lastCar.getOriginalType();
//车长配置,单位米 //车长配置,单位米
int carLength = 4; int carLength = 4;
//前车车辆类型
Integer agoCarType = agoCar.getOriginalType();
int agoCarLength = 4;
//TODO 不同车型长度配置
double distance = PtInPolyUtil.getDistance(agoCar.getLongitude(), agoCar.getLongitude(), lastCar.getLongitude(), lastCar.getLatitude());
double lastCarSpeed = lastCar.getSpeed() / 3.6; double lastCarSpeed = lastCar.getSpeed() / 3.6;
//计算车头时距(空当时间) (前车车尾到后车车头距离)/后车速度 //计算车头时距(空当时间)
// double time = (distance - carLength / 2 - agoCarLength / 2) / lastCarSpeed; double time = (lastCar.getGlobalTimeStamp() - agoCar.getGlobalTimeStamp()) / 1000.0
double time = (lastCar.getGlobalTimeStamp() - agoCar.getGlobalTimeStamp()) / 1000.0 - carLength / lastCarSpeed; - carLength / lastCarSpeed;
VehicleHeadTimeModel agoTimeModel = resultState.get(key); VehicleHeadTimeModel agoTimeModel = resultState.get(key);
if (agoTimeModel != null) { if (agoTimeModel != null) {
//空当时间累加 //空当时间累加
time = agoTimeModel.getHeadTime() + time; time += agoTimeModel.getHeadTime();
} }
VehicleHeadTimeModel timeModel = new VehicleHeadTimeModel(); VehicleHeadTimeModel timeModel = new VehicleHeadTimeModel();
...@@ -160,14 +161,15 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -160,14 +161,15 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
} else { } else {
mapState.put(key, lastCar); mapState.put(key, lastCar);
} }
} }
} }
} }
// 存在绿灯倒计时结束 if (!expiredGreenLightMap.isEmpty()) {
if(!expiredGreenLightMap.isEmpty()){ // 存在绿灯倒计时结束
for(Map.Entry<Integer, Integer> expiredLight: expiredGreenLightMap.entrySet()){ Iterator<Map.Entry<Integer, Integer>> iterator = expiredGreenLightMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, Integer> expiredLight = iterator.next();
Integer dir = expiredLight.getKey(); Integer dir = expiredLight.getKey();
Integer totalGreenLightTime = expiredLight.getValue(); Integer totalGreenLightTime = expiredLight.getValue();
...@@ -176,44 +178,48 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -176,44 +178,48 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
.filter(stat -> stat.getDir().compareTo(dir) == 0) .filter(stat -> stat.getDir().compareTo(dir) == 0)
.collect(Collectors.toList()); .collect(Collectors.toList());
//删除统计结果缓存 if (!stats.isEmpty()) {
Iterator<String> resultStateIterator = resultState.keys().iterator();
while (resultStateIterator.hasNext()){
String key = resultStateIterator.next();
if(key.startsWith(String.valueOf(dir))){
resultStateIterator.remove();
}
}
//删除车道相关缓存
Iterator<String> mapStateIterator = mapState.keys().iterator();
while (mapStateIterator.hasNext()){
String key = mapStateIterator.next();
if(key.startsWith(String.valueOf(dir))){
mapStateIterator.remove();
}
}
if(!stats.isEmpty()){
double average = stats.stream() double average = stats.stream()
.mapToDouble(VehicleHeadTimeModel::getHeadTime) .mapToDouble(VehicleHeadTimeModel::getHeadTime)
.summaryStatistics() .summaryStatistics()
.getAverage(); .getAverage();
double index = (totalGreenLightTime - average) / totalGreenLightTime;
double index = 0;
List<Long> lastCarTimeStampList = new ArrayList<>();
for (String key : mapState.keys()) {
if (key.startsWith(dir.toString())) {
CarTrackModel carTrackModel = mapState.get(key);
long globalTimeStamp = carTrackModel.getGlobalTimeStamp();
lastCarTimeStampList.add(globalTimeStamp);
}
}
if (!ObjectUtils.isEmpty(lastCarTimeStampList)) {
// 将空放时间计入空当时间
long currentTimeMillis = System.currentTimeMillis();
double average2 = lastCarTimeStampList.stream()
.mapToDouble(i -> currentTimeMillis - i)
.average().getAsDouble();
double finalAvg = average + average2;
index = (totalGreenLightTime - finalAvg) / totalGreenLightTime;
} else {
index = (totalGreenLightTime - average) / totalGreenLightTime;
}
double convertedIndex = convertIndex(index); // 转换非协调方向拥堵指数 double convertedIndex = convertIndex(index); // 转换非协调方向拥堵指数
String indexName; String indexName;
String congestionType; String congestionType;
if(convertedIndex <= 1.5){ if (convertedIndex <= 1.5) {
indexName = "畅通"; indexName = "畅通";
congestionType = CongestEnum.NO_CONGEST.getCode(); congestionType = CongestEnum.NO_CONGEST.getCode();
}else if(convertedIndex <= 2.0){ } else if (convertedIndex <= 2.0) {
indexName = "轻度拥堵"; indexName = "轻度拥堵";
congestionType = CongestEnum.LIGHT_CONGEST.getCode(); congestionType = CongestEnum.LIGHT_CONGEST.getCode();
}else if(convertedIndex < 3.0){ // 按照换算公式,最大只到3.0,因此这里不取等于 } else if (convertedIndex < 3.0) { // 按照换算公式,最大只到3.0,因此这里不取等于
indexName = "中度拥堵"; indexName = "中度拥堵";
congestionType = CongestEnum.MODERATE_CONGEST.getCode(); congestionType = CongestEnum.MODERATE_CONGEST.getCode();
}else{ } else {
indexName = "重度拥堵"; indexName = "重度拥堵";
congestionType = CongestEnum.HEAVY_CONGEST.getCode(); congestionType = CongestEnum.HEAVY_CONGEST.getCode();
} }
...@@ -226,14 +232,15 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -226,14 +232,15 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
long time = new Date().getTime(); long time = new Date().getTime();
stat.setGlobalTimeStamp(time); stat.setGlobalTimeStamp(time);
stat.setDetectTime(time); stat.setDetectTime(time);
stat.setIndexName(indexName);
stat.setCongestionCode(congestionType);
stat.setDir(dir); stat.setDir(dir);
boolean isCongestion = convertedIndex > 1.5; boolean isCongestion = convertedIndex > 1.5;
Integer stateKey = dir;
if (isCongestion) { if (isCongestion) {
try { try {
if (!dirState.contains(stateKey)) { if (!dirState.contains(dir)) {
StartDuration startDuration = new StartDuration(); StartDuration startDuration = new StartDuration();
// 获取当前的时间戳 // 获取当前的时间戳
Instant now = Instant.now(); Instant now = Instant.now();
...@@ -253,9 +260,9 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -253,9 +260,9 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
stat.setCongestionCode(congestionType); stat.setCongestionCode(congestionType);
startDuration.setCongestionCode(congestionType); startDuration.setCongestionCode(congestionType);
dirState.put(stateKey, startDuration); dirState.put(dir, startDuration);
} else { } else {
StartDuration startDuration = dirState.get(stateKey); StartDuration startDuration = dirState.get(dir);
Long startTimeMilli = startDuration.getStartTime(); Long startTimeMilli = startDuration.getStartTime();
stat.setStartTime(startTimeMilli); stat.setStartTime(startTimeMilli);
...@@ -270,7 +277,7 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -270,7 +277,7 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
String congestionCode = startDuration.getCongestionCode(); String congestionCode = startDuration.getCongestionCode();
String maxCongestionCode = calcMaxCongestionCode(congestionType, congestionCode); String maxCongestionCode = calcMaxCongestionCode(congestionType, congestionCode);
stat.setCongestionCode(maxCongestionCode); stat.setCongestionCode(maxCongestionCode);
dirState.put(stateKey, startDuration); dirState.put(dir, startDuration);
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
...@@ -279,9 +286,9 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -279,9 +286,9 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
// 删除状态 // 删除状态
try { try {
Iterator<Integer> dirStateKeysIter = dirState.keys().iterator(); Iterator<Integer> dirStateKeysIter = dirState.keys().iterator();
while (dirStateKeysIter.hasNext()){ while (dirStateKeysIter.hasNext()) {
Integer key = dirStateKeysIter.next(); Integer key = dirStateKeysIter.next();
if(key.equals(stateKey)){ if (key.equals(dir)) {
dirStateKeysIter.remove(); dirStateKeysIter.remove();
} }
} }
...@@ -290,7 +297,62 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String, ...@@ -290,7 +297,62 @@ public class VehicleGapTimeProcessFunction extends KeyedProcessFunction<String,
} }
} }
out.collect(stat); out.collect(stat);
} else {
// 无车或一辆车算畅通
CrossEventResult stat = new CrossEventResult();
stat.setCrossId(crossId);
stat.setCongestionCode(CongestEnum.NO_CONGEST.getType());
stat.setRid("");
stat.setIndex(1.5);
stat.setIndexName(CongestEnum.NO_CONGEST.getName());
long time = new Date().getTime();
stat.setGlobalTimeStamp(time);
stat.setDetectTime(time);
stat.setDir(dir);
// 删除状态
try {
Iterator<Integer> dirStateKeysIter = dirState.keys().iterator();
while (dirStateKeysIter.hasNext()) {
Integer key = dirStateKeysIter.next();
if (key.equals(dir)) {
dirStateKeysIter.remove();
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
out.collect(stat);
}
// 删除统计结果缓存
Iterator<String> resultStateIterator = resultState.keys().iterator();
while (resultStateIterator.hasNext()) {
String key = resultStateIterator.next();
if (key.startsWith(String.valueOf(dir))) {
resultStateIterator.remove();
}
} }
//删除车道相关缓存
Iterator<String> mapStateIterator = mapState.keys().iterator();
while (mapStateIterator.hasNext()) {
String key = mapStateIterator.next();
if (key.startsWith(String.valueOf(dir))) {
mapStateIterator.remove();
}
}
iterator.remove();
}
}
// 存储每个方向上一秒灯色
for (CrossRidTurnLampStatusModel model : ridLightStatusList) {
String turn = model.getTurn();
if (!turn.equals(Constant.PEDESTRAIN_LIGHT_CODE) && !turn.equals(Constant.RIGHT_LIGHT_CODE)) {
// 非行人灯,非右转灯
Integer dir = model.getDir();
String lampState = model.getLampState();
dirLastSecondState.put(dir, lampState);
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment