commit 0d79359080d0369b6f119d51294a6685baf64873 Author: 冯凯 <371894675@qq.com> Date: Thu Nov 30 18:41:57 2023 +0800 初始化 车辆解析系统 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..09bdfea --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c949e43 --- /dev/null +++ b/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + com.parseSystem + parseSystem + 3.6.3 + + + 17 + 17 + UTF-8 + + + + org.springframework.boot + spring-boot-starter + 2.7.15 + + + org.springframework.boot + spring-boot-starter-web + 2.7.15 + + + mysql + mysql-connector-java + 8.0.29 + + + + com.baomidou + mybatis-plus-boot-starter + 3.5.3.1 + + + org.apache.kafka + kafka-clients + 3.3.1 + + + org.projectlombok + lombok + 1.18.28 + compile + + + org.springframework.boot + spring-boot-starter-amqp + 2.7.15 + + + + + org.springframework.boot + spring-boot-starter-data-redis + 2.7.15 + + + com.alibaba + fastjson + 2.0.32 + + + com.dragon + dragon-common-redis + 3.6.3 + + + + + dragon-release + dragon-releases + http://10.100.1.7:8081/repository/maven-releases/ + + + + + dragon-public + dragon-maven + http://10.100.1.7:8081/repository/maven-public/ + + + public + aliyun nexus + http://10.100.1.7:8081/repository/maven-releases/ + + true + + + + diff --git a/src/main/java/com/parseSystem/ParseSystemApplication.java b/src/main/java/com/parseSystem/ParseSystemApplication.java new file mode 100644 index 0000000..864408c --- /dev/null +++ b/src/main/java/com/parseSystem/ParseSystemApplication.java @@ -0,0 +1,24 @@ +package com.parseSystem; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author 冯凯 + * @version 1.0 + * @description: + * @date 2023/11/25 15:34 + */ +@SpringBootApplication +public class ParseSystemApplication { + + /** + * 主方法 + * + * @param args 命令行参数 + */ + public static void main(String[] args) { + SpringApplication.run(ParseSystemApplication.class,args); + } + +} diff --git a/src/main/java/com/parseSystem/event/EventHandlerService.java b/src/main/java/com/parseSystem/event/EventHandlerService.java new file mode 100644 index 0000000..b70e3d2 --- /dev/null +++ b/src/main/java/com/parseSystem/event/EventHandlerService.java @@ -0,0 +1,89 @@ +package com.parseSystem.event; + +import com.alibaba.fastjson.JSONObject; +import com.dragon.common.redis.service.RedisService; +import com.parseSystem.utils.SpringUtils; +import com.parseSystem.vehicle.VehicleData; +import lombok.extern.log4j.Log4j2; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + *事件处理接口 + * @author 冯凯 + * @version 1.0 + * @description: + * @date 2023/11/27 20:54 + */ +@Component +@Log4j2 +public class EventHandlerService { + + @Autowired + private RedisService redisService; + + /** + * 事件处理map + */ + public static final Map> eventMap=new ConcurrentHashMap<>(); + + + + + + /** + * 注册事件 + * @param vin + * @param eventServiceName + */ + public void registerEvent(String vin,String eventServiceName){ + getEventList(vin).add(eventServiceName); + } + + /** + * 移除事件 + * @param vin + * @param eventServiceName + */ + public void removeEvent(String vin,String eventServiceName){ + getEventList(vin).remove(eventServiceName); + } + + /** + * 执行事件 + * @param vehicleData + */ + public void executeEvent(VehicleData vehicleData){ + List eventList = getEventList(vehicleData.getVin()); + eventList.forEach(eventServiceName -> { + VehicleEventService vehicleEventService = SpringUtils.getBean(eventServiceName); + vehicleEventService.executeEvent(vehicleData); + }); + } + + /** + * 获取事件列表 + * @param vin + * @return + */ + public List getEventList(String vin){ + List cacheList = redisService.getCacheList("event_VIN123456789"); + eventMap.put(vin,cacheList); + List eventList = eventMap.get(vin); + if (eventList==null){ + ArrayList list = new ArrayList<>(); + eventMap.put(vin,list); + } + return eventList; + } +} diff --git a/src/main/java/com/parseSystem/event/VehicleEventService.java b/src/main/java/com/parseSystem/event/VehicleEventService.java new file mode 100644 index 0000000..91e3c95 --- /dev/null +++ b/src/main/java/com/parseSystem/event/VehicleEventService.java @@ -0,0 +1,19 @@ +package com.parseSystem.event; + +import com.parseSystem.vehicle.VehicleData; + +/** + * + *事件执行接口 + * @author 冯凯 + * @version 1.0 + * @date 2023/11/27 22:45 + */ +public interface VehicleEventService { + + /** + * 事件执行抽象逻辑 + * @param vehicleData + */ + void executeEvent(VehicleData vehicleData); +} diff --git a/src/main/java/com/parseSystem/event/impl/FaultEvent.java b/src/main/java/com/parseSystem/event/impl/FaultEvent.java new file mode 100644 index 0000000..df3e53a --- /dev/null +++ b/src/main/java/com/parseSystem/event/impl/FaultEvent.java @@ -0,0 +1,27 @@ +package com.parseSystem.event.impl; + +import com.parseSystem.event.EventHandlerService; +import com.parseSystem.event.VehicleEventService; +import com.parseSystem.vehicle.VehicleData; +import org.springframework.stereotype.Service; + +/** + * + * 故障事件 + * @author 冯凯 + * @version 1.0 + * + * @date 2023/11/27 20:59 + */ +@Service("faultEvent") +public class FaultEvent extends EventHandlerService implements VehicleEventService { + + /** + * 故障事件执行逻辑 + * @param vehicleData + */ + @Override + public void executeEvent(VehicleData vehicleData) { + System.out.println("你好故障"); + } +} diff --git a/src/main/java/com/parseSystem/event/impl/FenceEvent.java b/src/main/java/com/parseSystem/event/impl/FenceEvent.java new file mode 100644 index 0000000..377a34e --- /dev/null +++ b/src/main/java/com/parseSystem/event/impl/FenceEvent.java @@ -0,0 +1,57 @@ +package com.parseSystem.event.impl; + +import com.dragon.common.redis.service.RedisService; +import com.parseSystem.event.EventHandlerService; +import com.parseSystem.event.VehicleEventService; +import com.parseSystem.utils.eventRuleJudge.PolygonUtil; +import com.parseSystem.vehicle.VehicleData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * + * 电子围栏事件 + * @author 冯凯 + * @version 1.0 + * + * @date 2023/11/27 20:57 + */ +@Service("fenceEvent") +public class FenceEvent extends EventHandlerService implements VehicleEventService { + + @Autowired + private RedisService redisService; + /** + * 电子围栏事件执行逻辑 + * @param vehicleData + */ + @Override + public void executeEvent(VehicleData vehicleData) { + String vin = vehicleData.getVin(); + List fenceList = redisService.getCacheList("fence_VIN123456789"); + Double latitude = Double.valueOf(vehicleData.getLatitude()); //实时纬度 + Double longitude = Double.valueOf(vehicleData.getLongitude()); + Point2D.Double point = new Point2D.Double(); + point.setLocation(longitude,latitude); + List pts = new ArrayList<>(); + fenceList.stream().forEach(item -> { + //循环得到每个电子围栏的坐标拼接的一个以;为分割点表示多边形的一个字符串 + List locationPts = Arrays.stream(item.split(";")) + .map(s -> s.split(",")) + .map(arr -> new Point2D.Double(Double.valueOf(arr[0]), Double.valueOf(arr[1]))) + .collect(Collectors.toList()); + boolean inPolygon = PolygonUtil.isInPolygon(point, locationPts); + if (inPolygon){ + System.out.println("在电子围栏内"); + }else{ + System.out.println("在电子围栏外"); + } + }); + } +} diff --git a/src/main/java/com/parseSystem/event/impl/HistoryTrackEvent.java b/src/main/java/com/parseSystem/event/impl/HistoryTrackEvent.java new file mode 100644 index 0000000..8c782e1 --- /dev/null +++ b/src/main/java/com/parseSystem/event/impl/HistoryTrackEvent.java @@ -0,0 +1,26 @@ +package com.parseSystem.event.impl; + +import com.parseSystem.event.EventHandlerService; +import com.parseSystem.event.VehicleEventService; +import com.parseSystem.vehicle.VehicleData; +import org.springframework.stereotype.Service; + +/** + * 历史轨迹事假 + * @author 冯凯 + * @version 1.0 + * + * @date 2023/11/27 20:59 + */ +@Service("historyTrackEvent") +public class HistoryTrackEvent extends EventHandlerService implements VehicleEventService { + + /** + * 历史轨迹执行逻辑 + * @param vehicleData + */ + @Override + public void executeEvent(VehicleData vehicleData) { + System.out.println("你好历史轨迹"); + } +} diff --git a/src/main/java/com/parseSystem/event/impl/RuntimeTraceEvent.java b/src/main/java/com/parseSystem/event/impl/RuntimeTraceEvent.java new file mode 100644 index 0000000..67aaa9b --- /dev/null +++ b/src/main/java/com/parseSystem/event/impl/RuntimeTraceEvent.java @@ -0,0 +1,27 @@ +package com.parseSystem.event.impl; + +import com.parseSystem.event.EventHandlerService; +import com.parseSystem.event.VehicleEventService; +import com.parseSystem.vehicle.VehicleData; +import org.springframework.stereotype.Service; + +/** + * + * 实时轨迹 + * @author 冯凯 + * @version 1.0 + * @description: 实时轨迹事假 + * @date 2023/11/27 20:58 + */ +@Service("runtimeTraceEvent") +public class RuntimeTraceEvent extends EventHandlerService implements VehicleEventService { + + /** + * 实时轨迹事件执行逻辑 + * @param vehicleData + */ + @Override + public void executeEvent(VehicleData vehicleData) { + System.out.println("你好实时轨迹"); + } +} diff --git a/src/main/java/com/parseSystem/kafka/ConsumerConfig/KafkaConsumerConfig.java b/src/main/java/com/parseSystem/kafka/ConsumerConfig/KafkaConsumerConfig.java new file mode 100644 index 0000000..f6c58f0 --- /dev/null +++ b/src/main/java/com/parseSystem/kafka/ConsumerConfig/KafkaConsumerConfig.java @@ -0,0 +1,31 @@ +package com.parseSystem.kafka.ConsumerConfig; + +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.util.Properties; + +/** + * @author 冯凯 + * @version 1.0 + * @description: + * @date 2023/11/25 15:37 + */ +@Component +public class KafkaConsumerConfig { + + @Bean + public KafkaConsumer consumerInit() { + KafkaConsumer consumer; + Properties properties = new Properties(); + properties.put("bootstrap.servers", "117.72.43.22:9092"); + properties.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); + properties.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); + properties.put("partitioner.class", "com.parseSystem.kafka.ConsumerConfig.MyPartitioner"); + consumer = new KafkaConsumer<>(properties); + return consumer; + } + + +} diff --git a/src/main/java/com/parseSystem/kafka/ConsumerConfig/MyPartitioner.java b/src/main/java/com/parseSystem/kafka/ConsumerConfig/MyPartitioner.java new file mode 100644 index 0000000..3545384 --- /dev/null +++ b/src/main/java/com/parseSystem/kafka/ConsumerConfig/MyPartitioner.java @@ -0,0 +1,43 @@ +package com.parseSystem.kafka.ConsumerConfig; + +import org.apache.kafka.clients.producer.Partitioner; +import org.apache.kafka.common.Cluster; +import org.apache.kafka.common.PartitionInfo; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +/** + * @author:fst + * @date:2023/11/25 + * @aim:自定义分区器 + */ +@Component +public class MyPartitioner implements Partitioner { + /** + * 自定义kafka分区主要解决用户分区数据倾斜问题 提高并发效率(假设 3 分区) + * @param topic 消息队列名 + * @param key 用户传入key + * @param keyBytes key字节数组 + * @param value 用户传入value + * @param valueBytes value字节数组 + * @param cluster 当前kafka节点数 + * @return 如果3个分区,返回 0 1 2 + */ + public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) { + //获取topic的partitions信息 + List partitionInfos = cluster.partitionsForTopic(topic); + int partitionsNum = partitionInfos.size(); + // 这里以 key 的哈希值作为分区选择依据 + System.out.println("--------------------------------------"); + System.out.println(Math.abs(key.hashCode()) % partitionsNum); + return Math.abs(key.hashCode()) % partitionsNum; + } + + public void close() { + } + + public void configure(Map map) { + } +} diff --git a/src/main/java/com/parseSystem/kafka/constant/A.java b/src/main/java/com/parseSystem/kafka/constant/A.java new file mode 100644 index 0000000..53c0870 --- /dev/null +++ b/src/main/java/com/parseSystem/kafka/constant/A.java @@ -0,0 +1,18 @@ +package com.parseSystem.kafka.constant; + +import java.security.Provider; + +/** + * @author 冯凯 + * @version 1.0 + * @description: + * @date 2023/11/27 10:27 + */ +public class A { + + public static void main(String[] args) { + System.out.println("=============启动类加载器================"); + Class aClass = A.class; + System.out.println(aClass.getClassLoader().getParent()); + } +} diff --git a/src/main/java/com/parseSystem/kafka/constant/kafkaConstants.java b/src/main/java/com/parseSystem/kafka/constant/kafkaConstants.java new file mode 100644 index 0000000..d905618 --- /dev/null +++ b/src/main/java/com/parseSystem/kafka/constant/kafkaConstants.java @@ -0,0 +1,25 @@ +package com.parseSystem.kafka.constant; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * + * kafka常量 + * @author 冯凯 + * @version 1.0 + * @date 2023/11/25 15:36 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class kafkaConstants { + + public String topic; + + private String partition; + public static final String BOOSTRAP_SERVERS="117.72.43.22:9092"; +} diff --git a/src/main/java/com/parseSystem/kafka/service/ConsumerService.java b/src/main/java/com/parseSystem/kafka/service/ConsumerService.java new file mode 100644 index 0000000..1f90445 --- /dev/null +++ b/src/main/java/com/parseSystem/kafka/service/ConsumerService.java @@ -0,0 +1,88 @@ +package com.parseSystem.kafka.service; + +import com.parseSystem.event.EventHandlerService; +import com.parseSystem.storage.service.StorageDateService; +import com.parseSystem.utils.ParseUtil; +import com.parseSystem.vehicle.VehicleData; +import lombok.extern.log4j.Log4j2; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.common.TopicPartition; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.time.Duration; +import java.util.Collections; + +/** + * @author 冯凯 + * @version 1.0 + * @description: + * @date 2023/11/25 15:52 + */ +@Service +@Log4j2 +public class ConsumerService { + +// /** +// * 注入kafka消费者 +// */ +// @Autowired +// private KafkaConsumer consumer; +// +// /** +// * 注入事件处理服务 +// */ +// @Autowired +// private EventHandlerService eventHandlerService; +// +// /** +// * 注入存储服务 +// */ +// @Autowired +// private StorageDateService storageDateService; +// +// /** +// * 在容器启动后自动执行的初始化方法 +// */ +// @PostConstruct +// public void consumerInit() { +// +// +// +// TopicPartition topicPartition = new TopicPartition("test", 0); +// +// // 订阅特定分区 +// consumer.assign(Collections.singleton(topicPartition)); +// //开启线程持续拉取数据 +// new Thread(() -> { +// while (true) { +// ConsumerRecords records = null; +// try { +// //每个一秒钟拉取一次 +// records = consumer.poll(Duration.ofMillis(1000)); +// for (ConsumerRecord record : records) { +// System.out.println(record.value()); +// //解析数据 +// String data = ParseUtil.sixteenToStr(record.value()); +// //构建数据对象 +// VehicleData vehicleData = VehicleData.getBuild(data); +// //存储数据到tiDB +// storageDateService.save(vehicleData); +// System.out.println(vehicleData); +// //调用执行事件 +// eventHandlerService.executeEvent(vehicleData); +// } +// } catch (Exception e) { +// log.info("records: {}", records); +// log.error(e); +// } +// } +// }).start(); +// } + + +} diff --git a/src/main/java/com/parseSystem/rabbitmq/ListenEventChangeRabbitMq.java b/src/main/java/com/parseSystem/rabbitmq/ListenEventChangeRabbitMq.java new file mode 100644 index 0000000..848e0ad --- /dev/null +++ b/src/main/java/com/parseSystem/rabbitmq/ListenEventChangeRabbitMq.java @@ -0,0 +1,107 @@ +package com.parseSystem.rabbitmq; + +import com.alibaba.fastjson.JSONObject; +import com.parseSystem.event.EventHandlerService; +import com.parseSystem.kafka.constant.kafkaConstants; +import com.parseSystem.storage.service.StorageDateService; +import com.parseSystem.utils.ParseUtil; +import com.parseSystem.vehicle.VehicleData; +import com.rabbitmq.client.Channel; +import lombok.extern.log4j.Log4j2; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.common.TopicPartition; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.Queue; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.time.Duration; +import java.util.Collections; + +/** + * + * 监听车辆事件变更消费队列 + * @author 冯凯 + * @version 1.0 + * + * @date 2023/11/27 22:19 + */ +@Component +@Log4j2 +public class ListenEventChangeRabbitMq { + @Autowired + private KafkaConsumer consumer; + @Autowired + private StorageDateService storageDateService; + + @Autowired + private EventHandlerService eventHandlerService; + + /** + * RabbitMQ消费者,订阅"kafka_top"队列中的消息并处理 + * + * @param mesg 接收到的消息内容 + * @param message RabbitMQ中的Message对象 + * @param channel RabbitMQ中的Channel对象 + */ + @RabbitListener(queuesToDeclare = {@Queue(value = "kafka_top")}) + public void consumerSubscribe(String mesg, Message message, Channel channel) { + log.info("收到准备订阅主题:" + mesg); + + // 将接收到的消息解析为kafkaConstants对象 + kafkaConstants kafkaConstants = JSONObject.parseObject(mesg, kafkaConstants.class); + + // 创建TopicPartition对象 + TopicPartition topicPartition = new TopicPartition(kafkaConstants.getTopic(), Integer.valueOf(kafkaConstants.getPartition())); + + try { + // 手动确认接收到的消息 + channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); + + // 将消费者订阅的主题设置为"kafka_top"队列的第一个分区 + consumer.assign(Collections.singleton(topicPartition)); + + // 开启线程持续拉取数据 + while (true) { + ConsumerRecords records = null; + try { + // 每个一秒钟拉取一次数据 + records = consumer.poll(Duration.ofMillis(1000)); + + for (ConsumerRecord record : records) { + System.out.println(record.value()); + + // 解析数据 + String data = ParseUtil.sixteenToStr(record.value()); + + // 构建数据对象 + VehicleData vehicleData = VehicleData.getBuild(data); + + // 存储数据到tiDB + storageDateService.save(vehicleData); + System.out.println(vehicleData); + + // 调用执行事件 + eventHandlerService.executeEvent(vehicleData); + } + } catch (Exception e) { + log.info("records: {}", records); + log.error(e); + } + } + + + // 订阅特定分区 + + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + +} diff --git a/src/main/java/com/parseSystem/storage/mapper/StorageDateMapper.java b/src/main/java/com/parseSystem/storage/mapper/StorageDateMapper.java new file mode 100644 index 0000000..3622e1d --- /dev/null +++ b/src/main/java/com/parseSystem/storage/mapper/StorageDateMapper.java @@ -0,0 +1,15 @@ +package com.parseSystem.storage.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.parseSystem.vehicle.VehicleData; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author 冯凯 + * @version 1.0 + * @description: + * @date 2023/11/28 15:14 + */ +@Mapper +public interface StorageDateMapper extends BaseMapper { +} diff --git a/src/main/java/com/parseSystem/storage/service/StorageDateService.java b/src/main/java/com/parseSystem/storage/service/StorageDateService.java new file mode 100644 index 0000000..0e430ac --- /dev/null +++ b/src/main/java/com/parseSystem/storage/service/StorageDateService.java @@ -0,0 +1,15 @@ +package com.parseSystem.storage.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.parseSystem.vehicle.VehicleData; + +/** + * @author 冯凯 + * @version 1.0 + * @description: 数据存储逻辑层 + * @date 2023/11/28 15:13 + */ +public interface StorageDateService extends IService { + + +} diff --git a/src/main/java/com/parseSystem/storage/service/impl/StorageDateServiceImpl.java b/src/main/java/com/parseSystem/storage/service/impl/StorageDateServiceImpl.java new file mode 100644 index 0000000..cf996d9 --- /dev/null +++ b/src/main/java/com/parseSystem/storage/service/impl/StorageDateServiceImpl.java @@ -0,0 +1,21 @@ +package com.parseSystem.storage.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.parseSystem.storage.mapper.StorageDateMapper; +import com.parseSystem.storage.service.StorageDateService; +import com.parseSystem.vehicle.VehicleData; +import org.springframework.stereotype.Service; + +import java.util.Collection; + +/** + * @author 冯凯 + * @version 1.0 + * @description: + * @date 2023/11/28 15:14 + */ +@Service +public class StorageDateServiceImpl extends ServiceImpl implements StorageDateService { + + +} diff --git a/src/main/java/com/parseSystem/utils/ParseUtil.java b/src/main/java/com/parseSystem/utils/ParseUtil.java new file mode 100644 index 0000000..3f11dfb --- /dev/null +++ b/src/main/java/com/parseSystem/utils/ParseUtil.java @@ -0,0 +1,21 @@ +package com.parseSystem.utils; + +/** + * 解析工具类 + * @author fengkai + * @version 1.0 + * @date 2023/11/26 22:11 + */ +public class ParseUtil { + + public static String sixteenToStr(String s) { + StringBuilder sb = new StringBuilder(); + String[] arr = s.split(" "); + int length = arr.length; + for (int i = 0; i < length; i++) { + int ch = Integer.parseInt(arr[i], 16); + sb.append((char) ch); + } + return sb.toString(); + } +} diff --git a/src/main/java/com/parseSystem/utils/SpringUtils.java b/src/main/java/com/parseSystem/utils/SpringUtils.java new file mode 100644 index 0000000..37176d1 --- /dev/null +++ b/src/main/java/com/parseSystem/utils/SpringUtils.java @@ -0,0 +1,103 @@ +package com.parseSystem.utils; + +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.stereotype.Component; + +/** + * spring工具类 方便在非spring管理环境中获取bean + * + * @author dragon + * + */ +@Component +public final class SpringUtils implements BeanFactoryPostProcessor { + /** + * Spring应用上下文环境 + */ + private static ConfigurableListableBeanFactory beanFactory; + + /** + * 获取对象 + * + * @param name + * @return Object 一个以所给名字注册的bean的实例 + * @throws BeansException + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) throws BeansException { + return (T) beanFactory.getBean(name); + } + + /** + * 获取类型为requiredType的对象 + * + * @param clz + * @return + * @throws BeansException + */ + public static T getBean(Class clz) throws BeansException { + T result = (T) beanFactory.getBean(clz); + return result; + } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) { + return beanFactory.containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws NoSuchBeanDefinitionException + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return beanFactory.isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws NoSuchBeanDefinitionException + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException { + return beanFactory.getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws NoSuchBeanDefinitionException + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return beanFactory.getAliases(name); + } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) { + return (T) AopContext.currentProxy(); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + SpringUtils.beanFactory = beanFactory; + } +} diff --git a/src/main/java/com/parseSystem/utils/eventRuleJudge/PolygonUtil.java b/src/main/java/com/parseSystem/utils/eventRuleJudge/PolygonUtil.java new file mode 100644 index 0000000..700ccba --- /dev/null +++ b/src/main/java/com/parseSystem/utils/eventRuleJudge/PolygonUtil.java @@ -0,0 +1,79 @@ +package com.parseSystem.utils.eventRuleJudge; + +import java.awt.geom.Point2D; +import java.util.List; + /** + * 电子围栏判定规则类 + */ +public class PolygonUtil { + /** + * 发现给定点是否在给定多边形内 + * @param point 给定点 + * @param pts 给定的多边形顶点列表 + * @return 如果给定点在多边形内,则返回true;否则返回false + */ + public static boolean isInPolygon(Point2D.Double point, List pts){ + int N = pts.size(); + boolean boundOrVertex = true; + int intersectCount = 0;//交叉点数量 + double precision = 2e-10;//浮点类型计算时候与0比较时候的容差 + Point2D.Double p1, p2;//临近顶点 + Point2D.Double p = point; //当前点 + + p1 = pts.get(0); + for (int i = 1; i <= N; i++) { + if(p.equals(p1)){ + return boundOrVertex; + } + + p2 = pts.get(i % N); + if(p.x < Math.min(p1.x,p2.x) || p.x > Math.max(p1.x, p2.x)){ + p1=p2; + continue; + } + + //射线穿过算法 + if(p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)){ + if(p.y <= Math.max(p1.y, p2.y)){ + if(p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)){ + return boundOrVertex; + } + + if(p1.y == p2.y){ + if(p1.y == p.y){ + return boundOrVertex; + }else{ + ++intersectCount; + } + }else{ + double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y; + if(Math.abs(p.y - xinters) < precision){ + return boundOrVertex; + } + + if(p.y < xinters){ + ++intersectCount; + } + } + } + }else{ + if(p.x == p2.x && p.y <= p2.y){ + Point2D.Double p3 = pts.get((i+1) % N); + + if(p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)){ + ++intersectCount; + intersectCount += 2 ; + } + } + } + p1 = p2; + } + if (intersectCount % 2 ==0){ + return false; + }else { + return true; + } + } + + +} diff --git a/src/main/java/com/parseSystem/vehicle/VehicleData.java b/src/main/java/com/parseSystem/vehicle/VehicleData.java new file mode 100644 index 0000000..674d31a --- /dev/null +++ b/src/main/java/com/parseSystem/vehicle/VehicleData.java @@ -0,0 +1,308 @@ +package com.parseSystem.vehicle; + + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +@TableName("vehicle_data") +public class VehicleData { + + /** + * 主键id + */ + @TableId(type = IdType.AUTO) + private Integer id; + + /** + * VIN + */ + private String vin; + + /** + * 时间戳 + */ + private Date createTime; + + /** + * 经度 + */ + private String longitude; + + /** + * 维度 + */ + private String latitude; + + /** + * 速度 + */ + private String speed; + + /** + * 里程 + */ + private BigDecimal mileage; + + /** + * 总电压 + */ + private String voltage; + + /** + * 总电流 + */ + private String current; + + /** + * 绝缘电阻 + */ + private String resistance; + + /** + * 档位 + */ + private String gear; + + /** + * 加速踏板行程值 + */ + private String accelerationPedal; + + /** + * 制动踏板行程值 + */ + private String brakePedal; + + /** + * 燃料消耗率 + */ + private String fuelConsumptionRate; + + /** + * 电机控制器温度 + */ + private String motorControllerTemperature; + + /** + * 电机转速 + */ + private String motorSpeed; + + /** + * 电机转矩 + */ + private String motorTorque; + + /** + * 电机温度 + */ + private String motorTemperature; + + /** + * 电机电压 + */ + private String motorVoltage; + + /** + * 电机电流 + */ + private String motorCurrent; + + /** + * 动力电池剩余电量SOC + */ + private BigDecimal remainingBattery; + + + /** + * 当前状态允许的最大反馈功率 + */ + private String maximumFeedbackPower; + + /** + * 当前状态允许最大放电功率 + */ + private String maximumDischargePower; + + /** + * BMS自检计数器 + */ + private String selfCheckCounter; + + /** + * 动力电池充放电电流 + */ + private String totalBatteryCurrent; + + /** + * 动力电池负载端总电压V3 + */ + private String totalBatteryVoltage; + + /** + * 单次最大电压 + */ + private String singleBatteryMaxVoltage; + + /** + * 单体电池最低电压 + */ + private String singleBatteryMinVoltage; + + /** + * 单体电池最高温度 + */ + private String singleBatteryMaxTemperature; + + /** + * 单体电池最低温度 + */ + private String singleBatteryMinTemperature; + + /** + * 动力电池可用容量 + */ + private String availableBatteryCapacity; + + /** + * 车辆状态 + */ + private int vehicleStatus; + + /** + * 充电状态 + */ + private int chargingStatus; + + /** + * 运行状态 + */ + private int operatingStatus; + + /** + * SOC + */ + private int socStatus; + + /** + * 可充电储能装置工作状态 + */ + private int chargingEnergyStorageStatus; + + /** + * 驱动电机状态 + */ + private int driveMotorStatus; + + /** + * 定位是否有效 + */ + private int positionStatus; + + /** + * EAS(汽车防盗系统)状态 + */ + private int easStatus; + + /** + * PTC(电动加热器)状态 + */ + private int ptcStatus; + + /** + * EPS(电动助力系统)状态 + */ + private int epsStatus; + + /** + * ABS(防抱死)状态 + */ + private int absStatus; + + /** + * MCU(电机/逆变器)状态 + */ + private int mcuStatus; + + /** + * 动力电池加热状态 + */ + private int heatingStatus; + + /** + * 动力电池当前状态 + */ + private int batteryStatus; + + /** + * 动力电池保温状态 + */ + private int batteryInsulationStatus; + + + public static VehicleData getBuild(String messages) { + char start = messages.charAt(0); + char end = messages.charAt(messages.length() - 1); + System.out.println(start); + System.out.println(end); + return VehicleData.builder() + .vin(messages.substring(1, 18)) + //messages.substring(18, 31) + .createTime(new Date()) + .longitude(messages.substring(31, 42)) + .latitude(messages.substring(42, 52)) + .speed(messages.substring(52, 58)) + .mileage(new BigDecimal(messages.substring(58, 69))) + .voltage(messages.substring(69, 75)) + .current(messages.substring(75, 80)) + .resistance(messages.substring(80, 89)) + .gear(messages.substring(89, 90)) + .accelerationPedal(messages.substring(90, 92)) + .brakePedal(messages.substring(92, 94)) + .fuelConsumptionRate(messages.substring(94, 99)) + .motorControllerTemperature(messages.substring(99, 105)) + .motorSpeed(messages.substring(105, 110)) + .motorTorque(messages.substring(110, 114)) + .motorTemperature(messages.substring(114, 120)) + .motorVoltage(messages.substring(120, 125)) + .motorCurrent(messages.substring(125, 133)) + .remainingBattery(new BigDecimal(messages.substring(133, 139))) + .maximumFeedbackPower(messages.substring(139, 145)) + .maximumDischargePower(messages.substring(145, 151)) + .selfCheckCounter(messages.substring(151, 153)) + .totalBatteryCurrent(messages.substring(153, 158)) + .totalBatteryVoltage(messages.substring(158, 164)) + .singleBatteryMaxVoltage(messages.substring(164, 168)) + .singleBatteryMinVoltage(messages.substring(168, 172)) + .singleBatteryMaxTemperature(messages.substring(172, 178)) + .singleBatteryMinTemperature(messages.substring(178, 184)) + .availableBatteryCapacity(messages.substring(184, 190)) + .vehicleStatus(Integer.valueOf(messages.substring(190, 191))) + .chargingStatus(Integer.valueOf(messages.substring(191, 192))) + .operatingStatus(Integer.valueOf(messages.substring(192, 193))) + .socStatus(Integer.valueOf(messages.substring(193, 194))) + .chargingEnergyStorageStatus(Integer.valueOf(messages.substring(194, 195))) + .driveMotorStatus(Integer.valueOf(messages.substring(195, 196))) + .positionStatus(Integer.valueOf(messages.substring(196, 197))) + .easStatus(Integer.valueOf(messages.substring(197, 198))) + .ptcStatus(Integer.valueOf(messages.substring(198, 199))) + .epsStatus(Integer.valueOf(messages.substring(199, 200))) + .absStatus(Integer.valueOf(messages.substring(200, 201))) + .mcuStatus(Integer.valueOf(messages.substring(201, 202))) + .heatingStatus(Integer.valueOf(messages.substring(202, 203))) + .batteryStatus(Integer.valueOf(messages.substring(203, 204))) + .batteryInsulationStatus(Integer.valueOf(messages.substring(204, 205))) + .build(); + + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..84ff9fe --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,27 @@ +spring: + redis: + host: 10.100.1.2 + port: 6379 + password: + application: + name: parseSystem + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://117.72.43.22:4000/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 + username: root + password: 123456 + rabbitmq: + host: 47.120.38.248 + port: 5672 + template: + mandatory: true + listener: + simple: + prefetch: 1 # 每次取一条消息消费 消费完成取下一条 + acknowledge-mode: manual # 设置消费端手动ack确认 + retry: + enabled: true # 支持重试 + publisher-confirms: true #确认消息已发送到交换机(Exchange) + publisher-returns: true #确认消息已发送到队列(Queue) +server: + port: 8066