更新事件

master
fst1996 2023-11-29 16:43:14 +08:00
parent 9cbc42d90a
commit ee09c901c2
14 changed files with 423 additions and 210 deletions

View File

@ -1,4 +1,4 @@
package com.god.data.server;
package com.god.data;
import com.god.common.security.annotation.EnableCustomConfig;
import com.god.common.security.annotation.EnableMyFeignClients;
@ -17,6 +17,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GodCarDataApplication {
public static void main (String[] args) {
SpringApplication.run(com.god.data.server.GodCarDataApplication.class, args);
SpringApplication.run(GodCarDataApplication.class);
}
}

View File

@ -0,0 +1,44 @@
package com.god.data.common.domain;
import lombok.Builder;
import lombok.Data;
/**
*
* @Author fst
* @date 2023/11/28 21:47
*/
@Data
@Builder
public class ElePoint {
/**
* id
*/
private Long id;
/**
*
*/
private String fenceName;
/**
* ;
*/
private String fenceLocation;
/**
* 0 1
*/
private Integer fenceStatus;
/**
* 1 2
*/
private Integer driveStatus;
/**
* vin
*/
private Long carVinId;
}

View File

@ -0,0 +1,26 @@
package com.god.data.common.domain;
import lombok.*;
/**
*
*/
@Data
@ToString
@Builder
@NoArgsConstructor
public class Point {
/**
* -180~180西
*/
private double lng;
/**
* -90~90
*/
private double lat;
public Point(double lng, double lat) {
this.lng = lng;
this.lat = lat;
}
}

View File

@ -14,6 +14,7 @@ import org.springframework.kafka.support.serializer.JsonDeserializer;
import java.util.List;
import java.util.Properties;
import static com.god.data.contents.KafkaContent.KAFKA_CON;
import static com.god.data.contents.KafkaContent.TOPIC;
/**
@ -24,66 +25,30 @@ import static com.god.data.contents.KafkaContent.TOPIC;
@Data
@Builder
@Configuration
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "spring.kafka.consumer")
public class KafkaConsumerConfig {
// kafka消费者服务器
private String bootstrapServers;
// 分组id
private String groupId;
// 是否自动提交偏移量默认为true为了避免出现重复数据和数据丢失设置为false手动提交
private boolean enableAutoCommit;
private Integer autoCommitInterval;
private String sessionTimeout;
private String maxPollIntervalTime;
private String maxPollRecords;
private String autoOffsetReset;
private String keyDeserializer;
private String valueDeserializer;
@Bean
public KafkaConsumer<String, String> consumerConfigs() {
Properties properties = new Properties();
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
properties.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
//是否自动提交偏移量默认值是true为了避免出现重复数据和数据丢失可以把它设置为false然后手动提交偏移量
properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, enableAutoCommit);
//自动提交的时间间隔,自动提交开启时生效
properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitInterval);
//该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下该作何处理:
//earliest当各分区下有已提交的offset时从提交的offset开始消费无提交的offset时从头开始消费分区的记录
//latest当各分区下有已提交的offset时从提交的offset开始消费无提交的offset时消费新产生的该分区下的数据在消费者启动之后生成的记录
//none当各分区都存在已提交的offset时从提交的offset开始消费只要有一个分区不存在已提交的offset则抛出异常
properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset);
//两次poll之间的最大间隔默认值为5分钟。如果超过这个间隔会触发reBalance
properties.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, maxPollIntervalTime);
//这个参数定义了poll方法最多可以拉取多少条消息默认值为500。如果在拉取消息的时候新消息不足500条那有多少返回多少如果超过500条每次只返回500。
//这个默认值在有些场景下太大有些场景很难保证能够在5min内处理完500条消息
//如果消费者无法在5分钟内处理完500条消息的话就会触发reBalance,
//然后这批消息会被分配到另一个消费者中,还是会处理不完,这样这批消息就永远也处理不完。
//要避免出现上述问题提前评估好处理一条消息最长需要多少时间然后覆盖默认的max.poll.records参数
//注需要开启BatchListener批量监听才会生效如果不开启BatchListener则不会出现reBalance情况
properties.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords);
//当broker多久没有收到consumer的心跳请求后就触发reBalance默认值是10s
properties.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, sessionTimeout);
//序列化建议使用Json这种序列化方式可以无需额外配置传输实体类
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
//设置分区器
properties.put("partitioner.class", "com.god.kafka.partitioner.MyPartitioner");
KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(properties);
consumer.subscribe(List.of(TOPIC));
return consumer;
public KafkaConsumer<String, String> consumerInit(){
Properties props = new Properties();
//设置kafka服务器地址
props.put("bootstrap.servers", KAFKA_CON);
//每个消费者分配独立的组号
props.put("group.id", "g2");
//如果value合法则自动提交偏移量
props.put("enable.auto.commit", "true");
//设置多久一次更新被消费消息的偏移量
props.put("auto.commit.interval.ms", "1000");
//设置会话响应的时间超过这个时间kafka可以选择放弃消费或者消费下一条消息
props.put("session.timeout.ms", "30000");
//自动重置offset
//earliest 在偏移量无效的情况下 消费者将从起始位置读取分区的记录
//latest 在偏移量无效的情况下 消费者将从最新位置读取分区的记录
props.put("auto.offset.reset","earliest");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
return new KafkaConsumer<>(props);
}
}

View File

@ -7,7 +7,7 @@ package com.god.data.contents;
*/
public class KafkaContent {
public static final String TOPIC = "top";
public static final String TOPIC = "test";
public static final String KAFKA_CON = "39.100.65.135:39092,39.100.65.135:29092,39.100.65.135:19092";
public static final String KAFKA_CON = "10.100.1.8:9092";
}

View File

@ -1,43 +0,0 @@
package com.god.data.partitioner;
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;
/**
* @authorfst
* @date2023/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<PartitionInfo> 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<String, ?> map) {
}
}

View File

@ -1,37 +0,0 @@
package com.god.data.rabbitmq.producer;
import com.god.data.common.domain.LogMessage;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.UUID;
/**
* - Producer
* @Component ProducerSpring
* 使SpringBootAMQP访rabbitmqAmqpTemplate
* rabbitmqstarter-amqpspringAmqpTemplate
*/
@Component
public class Sender {
@Autowired
private AmqpTemplate rabbitAmqpTemplate;
/*
*
*/
public void send(LogMessage msg){
/*
convertAndSend - template
javarabbitmqmessagerabbitmq
String
String
Object
*/
this.rabbitAmqpTemplate.convertAndSend(msg.getExchange(), UUID.randomUUID().toString(), msg);
}
}

View File

@ -3,18 +3,23 @@ package com.god.data.service;
import com.god.common.core.utils.SpringUtils;
import com.god.common.redis.service.RedisService;
import com.god.data.common.domain.CarMessage;
import com.god.data.service.impl.ElectronicFenceEvent;
import com.god.data.utils.AnalyzeUtils;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* kafka
* @author fst
@ -26,22 +31,22 @@ public class ParseDataService {
@Autowired
private RedisService redisService;
private final KafkaConsumer<String, String> consumer;
@Autowired
public ParseDataService(KafkaConsumer<String, String> consumer) {
this.consumer = consumer;
}
private KafkaConsumer<String, String> consumer;
@PostConstruct
public void start(){
new Thread(() -> {
consumer.subscribe(Arrays.asList("test"));
log.info("kafka数据解析服务启动");
while (true){
ConsumerRecords<String, String> records = null;
try {
//死循环拉取kafka数据
records = consumer.poll(Duration.ofMillis(100));
records = consumer.poll(Duration.ofMillis(1000));
for (ConsumerRecord<String, String> record : records) {
//把报文解析成对象
CarMessage carMessage = AnalyzeUtils.parseVehicleData(record.value());
//根据对象车辆vin获取事件集合从redis中获取
List<String> eventList = redisService.getCacheList("event" + carMessage.getVin());
@ -52,6 +57,7 @@ public class ParseDataService {
eventService.execute(carMessage);
}
}
System.out.println(record.offset() +" - "+ record.key() +" - "+ record.value());
}
}catch (Exception e){

View File

@ -1,8 +1,19 @@
package com.god.data.service.impl;
import com.alibaba.fastjson2.JSON;
import com.god.common.redis.service.RedisService;
import com.god.data.common.domain.CarMessage;
import com.god.data.common.domain.ElePoint;
import com.god.data.common.domain.Point;
import com.god.data.service.EventService;
import com.god.data.utils.GeofencingUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
@ -11,14 +22,61 @@ import org.springframework.stereotype.Service;
*/
@Service(value = "Fence")
public class ElectronicFenceEvent implements EventService {
@Autowired
private RedisService redisService;
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public void insert() {
}
@Override
public void execute(CarMessage carMessage) {
//从redis中获取当前车辆的电子围栏数据
List<ElePoint> list = redisService.getCacheList("Fence" + carMessage.getVin());
//根据当前经纬度和电子围栏数据进行判断,调用算法工具类
for (ElePoint elePoint : list) {
//获取电子围栏数据
String s = elePoint.getFenceLocation();
String[] split = s.split(";");
//转换为字符串集合,集合中字符串是 经度,纬度
List<String> strList = Arrays.asList(split);
//把字符串集合转换为Point集合point存放经纬度
List<Point> points = strList.stream()
.map(str -> {
String[] split1 = str.split(",");
return new Point(Double.parseDouble(split1[0]), Double.parseDouble(split1[1]));
}).collect(Collectors.toList());
//获取经纬度
Point point = new Point();
//把当前车辆的经纬度赋值给point对象
point.setLng(carMessage.getLongitude().doubleValue());
point.setLat(carMessage.getLatitude().doubleValue());
//判断车辆当前是否在点赞围栏中
boolean inPolygon = GeofencingUtils.isInPolygon(point, points);
//判断当前车辆是驶入/驶出围栏
if (elePoint.getDriveStatus().equals(1)){
//如果不在围栏范围内则,触发驶出电子围栏事件 存入rabbitmq中
if (!inPolygon){
rabbitTemplate.convertAndSend("OUT_FENCE", JSON.toJSON(elePoint), message -> {
message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
return message;
});
}
}
if (elePoint.getDriveStatus().equals(2)){
//如果不在围栏范围内则,触发驶入电子围栏事件 存入rabbitmq中
if (!inPolygon){
rabbitTemplate.convertAndSend("IN_FENCE", JSON.toJSON(elePoint), message -> {
message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
return message;
});
}
}
}
}
@Override

View File

@ -3,6 +3,7 @@ package com.god.data.service.impl;
import com.god.common.redis.service.RedisService;
import com.god.data.common.domain.CarMessage;
import com.god.data.service.EventService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -18,6 +19,8 @@ public class FaultAlarmEvent implements EventService {
@Autowired
private RedisService redisService;
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
@ -33,7 +36,10 @@ public class FaultAlarmEvent implements EventService {
if (carMessage.getBatteryStatus()==1){
strings.add("111");
}
//把对应的故障码存入rabbitmq
//把对应的故障码集合存入rabbitmq
if (strings.size()>0){
rabbitTemplate.convertAndSend("god.car.fault.alarm",strings);
}
}

View File

@ -1,7 +1,11 @@
package com.god.data.service.impl;
import com.god.common.redis.service.RedisService;
import com.god.data.common.domain.CarMessage;
import com.god.data.service.EventService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
@ -11,6 +15,16 @@ import org.springframework.stereotype.Service;
*/
@Service(value = "RealTimeTrajectory")
public class RealTimeTrajectoryEvent implements EventService {
@Autowired
private RedisService redisService;
// @Autowired
// private RedisTemplate<String,Object> redisTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public void insert() {
@ -18,7 +32,8 @@ public class RealTimeTrajectoryEvent implements EventService {
@Override
public void execute(CarMessage carMessage) {
//实时轨迹只需要把当前车辆的经纬度发送到redis集合即可
// redisTemplate.opsForList().set("Trajectory",1,carMessage);
}
@Override

View File

@ -15,76 +15,70 @@ public class AnalyzeUtils {
/**
*
*/
public static CarMessage parseVehicleData(String hexInput) {
//先去除空格
String inputString = hexInput.replaceAll(" ", "");
//调用工具类解析报文
String input = hexToString(inputString);
public static CarMessage parseVehicleData(String input) {
//把数据处理成java对象
CarMessage carMessage = new CarMessage();
CarMessage.builder()
.vin(input.substring(1, 17))
.timeString(Long.valueOf(input.substring(18, 30)))
.longitude(BigDecimal.valueOf(Double.parseDouble(input.substring(31, 41))))
.latitude(BigDecimal.valueOf(Double.parseDouble(input.substring(42, 51))))
.speed(BigDecimal.valueOf(Double.parseDouble(input.substring(52, 57))))
.sumMileage(BigDecimal.valueOf(Double.parseDouble(input.substring(58, 68))))
.sumVoltage(BigDecimal.valueOf(Double.parseDouble(input.substring(69, 74))))
.sumElectricity(BigDecimal.valueOf(Double.parseDouble(input.substring(75, 79))))
.sumResistance(BigDecimal.valueOf(Double.parseDouble(input.substring(80, 88))))
.gear(input.substring(89, 89))
.acceleratorPedal(BigDecimal.valueOf(Double.parseDouble(input.substring(90, 91))))
.brakePedal(BigDecimal.valueOf(Double.parseDouble(input.substring(92, 93))))
.specificFuelConsumption(BigDecimal.valueOf(Double.parseDouble(input.substring(94, 98))))
.motorControllerTemperature(BigDecimal.valueOf(Double.parseDouble(input.substring(99, 104))))
.motorSpeed(Long.valueOf(input.substring(105, 109)))
.motorTorque(Long.valueOf(input.substring(110, 113)))
.motorTemperature(BigDecimal.valueOf(Double.parseDouble(input.substring(114, 119))))
.motorTage(BigDecimal.valueOf(Double.parseDouble(input.substring(120, 124))))
.motorCurrent(BigDecimal.valueOf(Double.parseDouble(input.substring(125, 132))))
.remainingBattery(BigDecimal.valueOf(Double.parseDouble(input.substring(133, 138))))
.maximumFeedbackPower(BigDecimal.valueOf(Double.parseDouble(input.substring(139, 144))))
.maximumDischargePower(BigDecimal.valueOf(Double.parseDouble(input.substring(145, 150))))
.selfCheckCounter(Integer.valueOf(input.substring(151, 152)))
.totalBatteryCurrent(BigDecimal.valueOf(Double.parseDouble(input.substring(153, 157))))
.totalBatteryVoltage(BigDecimal.valueOf(Double.parseDouble(input.substring(158, 163))))
.singleBatteryMaxVoltage(BigDecimal.valueOf(Double.parseDouble(input.substring(164, 167))))
.singleBatteryMinVoltage(BigDecimal.valueOf(Double.parseDouble(input.substring(168, 171))))
.singleBatteryMaxTemperature(BigDecimal.valueOf(Double.parseDouble(input.substring(172, 177))))
.singleBatteryMinTemperature(BigDecimal.valueOf(Double.parseDouble(input.substring(178, 183))))
.availableBatteryCapacity(BigDecimal.valueOf(Double.parseDouble(input.substring(184, 189))))
.vehicleStatus(Integer.valueOf(input.substring(190, 190)))
.chargingStatus(Integer.valueOf(input.substring(191, 191)))
.operatingStatus(Integer.valueOf(input.substring(192, 192)))
.socStatus(Integer.valueOf(input.substring(193, 193)))
.chargingEnergyStorageStatus(Integer.valueOf(input.substring(194, 194)))
.driveMotorStatus(Integer.valueOf(input.substring(195, 195)))
.positionStatus(Integer.valueOf(input.substring(196, 196)))
.easStatus(Integer.valueOf(input.substring(197, 197)))
.ptcStatus(Integer.valueOf(input.substring(198, 198)))
.epsStatus(Integer.valueOf(input.substring(199, 199)))
.absStatus(Integer.valueOf(input.substring(200, 200)))
.mcuStatus(Integer.valueOf(input.substring(201, 201)))
.heatingStatus(Integer.valueOf(input.substring(202, 202)))
.batteryStatus(Integer.valueOf(input.substring(203, 203)))
.batteryInsulationStatus(Integer.valueOf(input.substring(204, 204)))
.dcdcStatus(Integer.valueOf(input.substring(205, 205)))
.chgStatus(Integer.valueOf(input.substring(206, 206)));
.timeString(Long.valueOf(input.substring(17, 30)))
.longitude(BigDecimal.valueOf(Double.parseDouble(input.substring(30, 41))))
.latitude(BigDecimal.valueOf(Double.parseDouble(input.substring(41, 51))))
.speed(BigDecimal.valueOf(Double.parseDouble(input.substring(51, 57))))
.sumMileage(BigDecimal.valueOf(Double.parseDouble(input.substring(57, 68))))
.sumVoltage(BigDecimal.valueOf(Double.parseDouble(input.substring(68, 74))))
.sumElectricity(BigDecimal.valueOf(Double.parseDouble(input.substring(74, 79))))
.sumResistance(BigDecimal.valueOf(Double.parseDouble(input.substring(79, 88))))
.gear(input.substring(88, 89))
.acceleratorPedal(BigDecimal.valueOf(Double.parseDouble(input.substring(89, 91))))
.brakePedal(BigDecimal.valueOf(Double.parseDouble(input.substring(91, 93))))
.specificFuelConsumption(BigDecimal.valueOf(Double.parseDouble(input.substring(93, 98))))
.motorControllerTemperature(BigDecimal.valueOf(Double.parseDouble(input.substring(98, 104))))
.motorSpeed(Long.valueOf(input.substring(104, 109)))
.motorTorque(Long.valueOf(input.substring(109, 113)))
.motorTemperature(BigDecimal.valueOf(Double.parseDouble(input.substring(113, 119))))
.motorTage(BigDecimal.valueOf(Double.parseDouble(input.substring(119, 124))))
.motorCurrent(BigDecimal.valueOf(Double.parseDouble(input.substring(124, 132))))
.remainingBattery(BigDecimal.valueOf(Double.parseDouble(input.substring(132, 138))))
.maximumFeedbackPower(BigDecimal.valueOf(Double.parseDouble(input.substring(138, 144))))
.maximumDischargePower(BigDecimal.valueOf(Double.parseDouble(input.substring(144, 150))))
.selfCheckCounter(Integer.valueOf(input.substring(150, 152)))
.totalBatteryCurrent(BigDecimal.valueOf(Double.parseDouble(input.substring(152, 157))))
.totalBatteryVoltage(BigDecimal.valueOf(Double.parseDouble(input.substring(157, 163))))
.singleBatteryMaxVoltage(BigDecimal.valueOf(Double.parseDouble(input.substring(163, 167))))
.singleBatteryMinVoltage(BigDecimal.valueOf(Double.parseDouble(input.substring(167, 171))))
.singleBatteryMaxTemperature(BigDecimal.valueOf(Double.parseDouble(input.substring(171, 177))))
.singleBatteryMinTemperature(BigDecimal.valueOf(Double.parseDouble(input.substring(177, 183))))
.availableBatteryCapacity(BigDecimal.valueOf(Double.parseDouble(input.substring(183, 189))))
.vehicleStatus(Integer.valueOf(input.substring(189, 190)))
.chargingStatus(Integer.valueOf(input.substring(190, 191)))
.operatingStatus(Integer.valueOf(input.substring(191, 192)))
.socStatus(Integer.valueOf(input.substring(192, 193)))
.chargingEnergyStorageStatus(Integer.valueOf(input.substring(193, 194)))
.driveMotorStatus(Integer.valueOf(input.substring(194, 195)))
.positionStatus(Integer.valueOf(input.substring(195, 196)))
.easStatus(Integer.valueOf(input.substring(196, 197)))
.ptcStatus(Integer.valueOf(input.substring(197, 198)))
.epsStatus(Integer.valueOf(input.substring(198, 199)))
.absStatus(Integer.valueOf(input.substring(199, 200)))
.mcuStatus(Integer.valueOf(input.substring(200, 201)))
.heatingStatus(Integer.valueOf(input.substring(201, 202)))
.batteryStatus(Integer.valueOf(input.substring(202, 203)))
.batteryInsulationStatus(Integer.valueOf(input.substring(203, 204)))
.dcdcStatus(Integer.valueOf(input.substring(204, 205)))
.chgStatus(Integer.valueOf(input.substring(205, 206)));
//返回解析完的对象
return carMessage;
}
private static String hexToString(String hex) {
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i += 2) {
String str = hex.substring(i, i + 2);
output.append((char) Integer.parseInt(str, 16));
}
return output.toString();
public static void main(String[] args) {
CarMessage carMessage = parseVehicleData("~VIN12345678912345170124349622700000000000000000000000000012.5000000000000000000000000000P000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000011111111111111111©~");
System.out.println(carMessage);
}
}

View File

@ -0,0 +1,179 @@
package com.god.data.utils;
import com.god.data.common.domain.Point;
import java.util.Arrays;
import java.util.List;
/**
*
* @author : fst
* @version : 1.0.0
* @date: 2023-11-28 21:02:54
*/
public class GeofencingUtils {
/**
* ()
*/
private static final double EARTH_RADIUS = 6378137.0;
private static double rad(double d) {
return d * Math.PI / 180.0;
}
/**
*
* @param radius /
* @param p1
* @param p2
* @return: boolean true:,false:
* @date: 2021-11-08 09:44:54
*/
public static boolean isInCircle(double radius, Point p1, Point p2) {
double radLat1 = rad(p1.getLat());
double radLat2 = rad(p2.getLat());
double a = radLat1 - radLat2;
double b = rad(p1.getLng()) - rad(p2.getLng());
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * EARTH_RADIUS;
s = Math.round(s * 10000) / 10000;
return !(s > radius);
}
/**
*
* @param lng
* @param lat
* @param minLng
* @param maxLng
* @param minLat
* @param maxLat
* @return boolean true:, false:
* @Title: isInArea
*/
public static boolean isInRectangleArea(double lng, double lat, double minLng, double maxLng,
double minLat, double maxLat) {
if (isInRange(lat, minLat, maxLat)) {//如果在纬度的范围内
if (minLng * maxLng > 0) {
return isInRange(lng, minLng, maxLng);
} else {
if (Math.abs(minLng) + Math.abs(maxLng) < 180) {
return isInRange(lng, minLng, maxLng);
} else {
double left = Math.max(minLng, maxLng);
double right = Math.min(minLng, maxLng);
return isInRange(lng, left, 180) || isInRange(lng, right, -180);
}
}
} else {
return false;
}
}
/**
*
* @param point
* @param gpsPoints GPS
* @return boolean true:, false:
* @Title: isInArea
*/
public static boolean isInRectangleArea(Point point, Point[] gpsPoints) {
if (gpsPoints.length != 4) {
return false;
}
double[] lats = new double[4];
double[] lngs = new double[4];
for (int i = 0; i < gpsPoints.length; i++) {
lats[i] = gpsPoints[i].getLat();
lngs[i] = gpsPoints[i].getLng();
}
Arrays.sort(lats);
Arrays.sort(lngs);
return isInRectangleArea(point.getLat(), point.getLng(), lats[0], lats[3], lngs[0], lngs[3]);
}
/**
*
* @param point
* @param left
* @param right
* @return boolean
*/
public static boolean isInRange(double point, double left, double right) {
return point >= Math.min(left, right) && point <= Math.max(left, right);
}
/**
*
* @param point
* @param pts
* @return boolean true:, false:
* @throws
* @Title: IsPointInPoly
*/
public static boolean isInPolygon(Point point, List<Point> pts) {
int N = pts.size();
boolean boundOrVertex = true;
int intersectCount = 0;//交叉点数量
double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
Point p1, p2;//临近顶点
Point 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.getLng() < Math.min(p1.getLng(), p2.getLng()) || p.getLng() > Math.max(p1.getLng(), p2.getLng())) {
p1 = p2;
continue;
}
//射线穿过算法
if (p.getLng() > Math.min(p1.getLng(), p2.getLng()) && p.getLng() < Math.max(p1.getLng(), p2.getLng())) {
if (p.getLat() <= Math.max(p1.getLat(), p2.getLat())) {
if (p1.getLng() == p2.getLng() && p.getLat() >= Math.min(p1.getLat(), p2.getLat())) {
return boundOrVertex;
}
if (p1.getLat() == p2.getLat()) {
if (p1.getLat() == p.getLat()) {
return boundOrVertex;
} else {
++intersectCount;
}
} else {
double xinters = (p.getLng() - p1.getLng()) * (p2.getLat() - p1.getLat()) / (p2.getLng() - p1.getLng()) + p1.getLat();
if (Math.abs(p.getLat() - xinters) < precision) {
return boundOrVertex;
}
if (p.getLat() < xinters) {
++intersectCount;
}
}
}
} else {
if (p.getLng() == p2.getLng() && p.getLat() <= p2.getLat()) {
Point p3 = pts.get((i + 1) % N);
if (p.getLng() >= Math.min(p1.getLng(), p3.getLng()) && p.getLng() <= Math.max(p1.getLng(), p3.getLng())) {
++intersectCount;
} else {
intersectCount += 2;
}
}
}
p1 = p2;
}
return intersectCount % 2 != 0;
}
}

View File

@ -29,7 +29,7 @@ spring:
# kafka消费者服务器
bootstrap-servers: 10.100.1.8:9092
# 分组id
group-id: firstGroup
group-id: fst001
# 指定了消费者读取了一个没有偏移量的分区获取偏移量无效的情况下该如何处理
# earliest当各分区下有已提交的offset时从提交的offset开始消费无提交的offset时从头开始消费分区的记录
# latest当各分区下有已提交的offset时从提交的offset开始消费无提交的offset时消费新产生的该分区下的数据在消费者启动之后生成的记录