事件处理模块初始化

master
刘武 2024-09-29 10:55:32 +08:00
parent ff02ae0b56
commit 05bc325434
33 changed files with 1593 additions and 0 deletions

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>cloud-modules</artifactId>
<version>3.6.3</version>
</parent>
<artifactId>cloud-event</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<description>
cloud-event 数据处理
</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>4.1.2</version>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- MuYu Common DataSource -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-datasource</artifactId>
</dependency>
<!-- MuYu Common DataScope -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-datascope</artifactId>
</dependency>
<!-- MuYu Common Log -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-log</artifactId>
</dependency>
<!-- 接口模块 -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-api-doc</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.iotdb</groupId>
<artifactId>iotdb-session</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.iotdb</groupId>
<artifactId>node-commons</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,13 @@
package com.muyu.event;
import com.muyu.common.security.annotation.EnableMyFeignClients;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableMyFeignClients
public class EventApplication {
public static void main(String[] args) {
SpringApplication.run(EventApplication.class,args);
}
}

View File

@ -0,0 +1,25 @@
package com.muyu.event.basics;
/**
* @author
* @package
* @nameEventHandler
* @date2024/9/29
*/
public class EventHandler {
private static final ThreadLocal<EventQueueConfig> EVENT_THREAD = new ThreadLocal<>();
public static void set(final EventQueueConfig handler) {
EVENT_THREAD.set(handler);
}
public static EventQueueConfig get() {
return EVENT_THREAD.get();
}
public static void remove(){
EVENT_THREAD.remove();
}
}

View File

@ -0,0 +1,25 @@
package com.muyu.event.basics;
public abstract class EventProcessBasics {
/**
*
*/
protected EventProcessBasics nextEvent;
/**
*
* @param nextHandler
*/
public void setNextHandler(EventProcessBasics nextHandler) {
this.nextEvent = nextHandler;
}
/**
*
* @param eventKey key
*/
public abstract void handleEvent(String eventKey);
}

View File

@ -0,0 +1,35 @@
package com.muyu.event.basics;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.concurrent.LinkedBlockingDeque;
/**
* @author
* @package
* @nameEventQueueConfig
* @date2024/9/29
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EventQueueConfig {
private LinkedBlockingDeque<EventProcessBasics> taskNodeQueue = new LinkedBlockingDeque<>();
public void addEvent(EventProcessBasics obj){
this.taskNodeQueue.add(obj);
}
public boolean hashEventNext(){
return !taskNodeQueue.isEmpty();
}
private EventProcessBasics nextTaskNode(){
return taskNodeQueue.poll();
}
}

View File

@ -0,0 +1,28 @@
package com.muyu.event.basics;
import com.muyu.event.domian.EventActuate;
import org.springframework.context.ApplicationEvent;
import java.util.List;
/**
* @author
* @package
* @nameStartEvent
* @date2024/9/29
*/
public class StartEvent extends ApplicationEvent {
private EventActuate eventActuate;
public StartEvent(EventActuate source) {
super(source);
this.eventActuate = source;
}
public EventActuate getEventActuate() {
return eventActuate;
}
}

View File

@ -0,0 +1,128 @@
package com.muyu.event.config;
import com.muyu.event.domian.CarInformation;
import org.apache.iotdb.isession.SessionDataSet;
import org.apache.iotdb.isession.util.Version;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.Session;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.read.common.Field;
import org.apache.iotdb.tsfile.read.common.RowRecord;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* iotdb
* @author
* @packagecom.muyu.event.config
* @nameIOTDBConfig
* @date2024/9/28 19:35
*/
@Configuration
public class IoTDBConfig {
public static final String HOST="47.116.173.119";
public static final Integer PORT=6667;
public static final String USERNAME="root";
public static final String PASSWORD="root";
public static final String TABLENAME="root.four.car_information";
/**
*
* @return
*/
public Session initIoTDB(){
// 初始化与连接
Session session = new Session.Builder()
.host(HOST)
.port(PORT)
.username(USERNAME)
.password(PASSWORD)
.version(Version.V_1_0)
.build();
return session;
};
/**
*
* @param list
*/
public void insertIoTDB(List<String> list){
Session session = initIoTDB();
// 开启session Rpc不压缩
try {
session.open(false);
//添加字段名称
ArrayList<String> measurements = new ArrayList<>();
//添加字段类型
ArrayList<TSDataType> types = new ArrayList<>();
measurements.add("car_vin");
measurements.add("information");
session.insertRecord(TABLENAME,System.currentTimeMillis(),measurements,list);
//关闭连接
session.close();
} catch (IoTDBConnectionException e) {
throw new RuntimeException(e);
} catch (StatementExecutionException e) {
throw new RuntimeException(e);
}
}
public CarInformation queryIoTDB(String carVin) {
Session session = initIoTDB();
try {
session.open(false);
} catch (IoTDBConnectionException e) {
throw new RuntimeException(e);
}
Long timeMillis = System.currentTimeMillis();
CarInformation carInformation = new CarInformation();
try(SessionDataSet dataSet= session.executeQueryStatement("select * from root.four.car_information where car_vin='"+carVin+"'")){
System.out.println(dataSet.getColumnNames());
dataSet.setFetchSize(1024);
while (dataSet.hasNext()){
// List<Field> fields = dataSet.next().getFields();
// carInformation.setCarVin(String.valueOf(fields.get(0)));
// carInformation.setInformation(String.valueOf(fields.get(1)));
String[] fields = dataSet.next().toString().split("\t");
carInformation.setTime(Long.valueOf(fields[0]));
carInformation.setCarVin(fields[1]);
carInformation.setInformation(fields[2]);
}
} catch (IoTDBConnectionException e) {
throw new RuntimeException(e);
} catch (StatementExecutionException e) {
throw new RuntimeException(e);
}
//关闭连接
try {
session.close();
} catch (IoTDBConnectionException e) {
throw new RuntimeException(e);
}
return carInformation;
};
}

View File

@ -0,0 +1,129 @@
package com.muyu.event.config;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.config.KafkaListenerContainerFactory;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
import org.springframework.kafka.listener.ContainerProperties;
import org.springframework.kafka.support.serializer.JsonDeserializer;
import java.util.HashMap;
import java.util.Map;
/**
* @author
* @date 2022/10/31 18:05
* kafkaymlyml
*/
@SpringBootConfiguration
public class KafkaConsumerConfig {
/**
* Kafka
*/
@Value("${spring.kafka.consumer.bootstrap-servers}")
private String bootstrapServers;
/**
*
*/
@Value("${spring.kafka.consumer.group-id}")
private String groupId;
/**
*
*/
@Value("${spring.kafka.consumer.enable-auto-commit}")
private boolean enableAutoCommit;
/**
* Kafka
*/
@Value("${spring.kafka.properties.session.timeout.ms}")
private String sessionTimeout;
/**
* poll5reBalance
*/
@Value("${spring.kafka.properties.max.poll.interval.ms}")
private String maxPollIntervalTime;
@Value("${spring.kafka.consumer.max-poll-records}")
private String maxPollRecords;
@Value("${spring.kafka.consumer.auto-offset-reset}")
private String autoOffsetReset;
@Value("${spring.kafka.listener.concurrency}")
private Integer concurrency;
@Value("${spring.kafka.listener.missing-topics-fatal}")
private boolean missingTopicsFatal;
@Value("${spring.kafka.listener.poll-timeout}")
private long pollTimeout;
@Bean
public Map<String, Object> consumerConfigs() {
Map<String, Object> propsMap = new HashMap<>(16);
propsMap.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
propsMap.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
//是否自动提交偏移量默认值是true为了避免出现重复数据和数据丢失可以把它设置为false然后手动提交偏移量
propsMap.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, enableAutoCommit);
//自动提交的时间间隔,自动提交开启时生效
propsMap.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "2000");
//该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下该作何处理:
//earliest当各分区下有已提交的offset时从提交的offset开始消费无提交的offset时从头开始消费分区的记录
//latest当各分区下有已提交的offset时从提交的offset开始消费无提交的offset时消费新产生的该分区下的数据在消费者启动之后生成的记录
//none当各分区都存在已提交的offset时从提交的offset开始消费只要有一个分区不存在已提交的offset则抛出异常
propsMap.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset);
//两次poll之间的最大间隔默认值为5分钟。如果超过这个间隔会触发reBalance
propsMap.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, maxPollIntervalTime);
//这个参数定义了poll方法最多可以拉取多少条消息默认值为500。如果在拉取消息的时候新消息不足500条那有多少返回多少如果超过500条每次只返回500。
//这个默认值在有些场景下太大有些场景很难保证能够在5min内处理完500条消息
//如果消费者无法在5分钟内处理完500条消息的话就会触发reBalance,
//然后这批消息会被分配到另一个消费者中,还是会处理不完,这样这批消息就永远也处理不完。
//要避免出现上述问题提前评估好处理一条消息最长需要多少时间然后覆盖默认的max.poll.records参数
//注需要开启BatchListener批量监听才会生效如果不开启BatchListener则不会出现reBalance情况
propsMap.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords);
//当broker多久没有收到consumer的心跳请求后就触发reBalance默认值是10s
propsMap.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, sessionTimeout);
//序列化建议使用Json这种序列化方式可以无需额外配置传输实体类
propsMap.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
propsMap.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
return propsMap;
}
@Bean
public ConsumerFactory<Object, Object> consumerFactory() {
// 配置消费者的 Json 反序列化的可信赖包,反序列化实体类需要
try (JsonDeserializer<Object> deserializer = new JsonDeserializer<>()) {
deserializer.trustedPackages("*");
return new DefaultKafkaConsumerFactory<>(consumerConfigs(), new JsonDeserializer<>(), deserializer);
}
}
/**
* kafka Kafka
* @return
*/
@Bean
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<Object, Object>> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<Object, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
//在侦听器容器中运行的线程数,一般设置为 机器数*分区数
factory.setConcurrency(concurrency);
// 消费监听接口监听的主题不存在时默认会报错所以设置为false忽略错误
factory.setMissingTopicsFatal(missingTopicsFatal);
// 自动提交关闭,需要设置手动消息确认
factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
factory.getContainerProperties().setPollTimeout(pollTimeout);
// 设置为批量监听需要用List接收
// factory.setBatchListener(true);
return factory;
}
}

View File

@ -0,0 +1,127 @@
package com.muyu.event.config;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import org.springframework.kafka.transaction.KafkaTransactionManager;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
@Configuration
public class KafkaProviderConfig {
/**
* kafka
*/
@Value("${spring.kafka.producer.bootstrap-servers}")
private String bootstrapServers;
/**
* Kafka
*/
@Value("${spring.kafka.producer.transaction-id-prefix}")
private String transactionIdPrefix;
/**
*
*/
@Value("${spring.kafka.producer.acks}")
private String acks;
/**
*
*/
@Value("${spring.kafka.producer.retries}")
private String retries;
/**
*
*/
@Value("${spring.kafka.producer.batch-size}")
private String batchSize;
/**
*
*/
@Value("${spring.kafka.producer.buffer-memory}")
private String bufferMemory;
/**
*
*/
@Value("${spring.kafka.producer.key-serializer}")
private String keySerializer;
/**
*
*/
@Value("${spring.kafka.producer.value-serializer}")
private String valueSerializer;
/**
* map
* @return
*/
@Bean
public Map<String, Object> producerConfigs() {
Map<String, Object> props = new HashMap<>(16);
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
//acks=0 生产者在成功写入消息之前不会等待任何来自服务器的响应。
//acks=1 只要集群的首领节点收到消息,生产者就会收到一个来自服务器成功响应。
//acks=all :只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。
//开启事务必须设为all
props.put(ProducerConfig.ACKS_CONFIG, acks);
//发生错误后消息重发的次数开启事务必须大于0
props.put(ProducerConfig.RETRIES_CONFIG, retries);
//当多个消息发送到相同分区时,生产者会将消息打包到一起,以减少请求交互. 而不是一条条发送
//批次的大小可以通过batch.size 参数设置.默认是16KB
//较小的批次大小有可能降低吞吐量批次大小为0则完全禁用批处理
//比如说kafka里的消息5秒钟Batch才凑满了16KB才能发送出去。那这些消息的延迟就是5秒钟
//实测batchSize这个参数没有用
props.put(ProducerConfig.BATCH_SIZE_CONFIG, batchSize);
//有的时刻消息比较少,过了很久,比如5min也没有凑够16KB,这样延时就很大,所以需要一个参数. 再设置一个时间,到了这个时间,
//即使数据没达到16KB,也将这个批次发送出去
props.put(ProducerConfig.LINGER_MS_CONFIG, "5000");
//生产者内存缓冲区的大小
props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, bufferMemory);
//反序列化,和生产者的序列化方式对应
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, keySerializer);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, valueSerializer);
return props;
}
/**
*
* @return
*/
@Bean
public ProducerFactory<Object, Object> producerFactory() {
DefaultKafkaProducerFactory<Object, Object> factory = new DefaultKafkaProducerFactory<>(producerConfigs());
//开启事务,会导致 LINGER_MS_CONFIG 配置失效
factory.setTransactionIdPrefix(transactionIdPrefix);
return factory;
}
/**
* Kafka
* @param producerFactory
* @return
*/
@Bean
public KafkaTransactionManager<Object, Object> kafkaTransactionManager(ProducerFactory<Object, Object> producerFactory) {
return new KafkaTransactionManager<>(producerFactory);
}
/**
* KafkaTemplate
* @return
*/
@Bean
public KafkaTemplate<Object, Object> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
}

View File

@ -0,0 +1,65 @@
package com.muyu.event.config;
import jakarta.annotation.Nullable;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.ProducerListener;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class KafkaSendResultHandler implements ProducerListener<Object,Object> {
@Autowired
private KafkaTemplate<Object,Object> kafkaTemplate;
/**
* bean
*/
@PostConstruct
public void init(){
this.kafkaTemplate.setProducerListener(this);
}
/**
* Kafka
* @param producerRecord
* @param recordMetadata
*/
@Override
public void onSuccess(ProducerRecord producerRecord, RecordMetadata recordMetadata){
System.out.println("信息发送成功:"+ producerRecord.toString());
}
/**
* Kafka
* @param producerRecord the failed record
* @param recordMetadata The metadata for the record that was sent (i.e. the partition
* and offset). If an error occurred, metadata will contain only valid topic and maybe
* the partition. If the partition is not provided in the ProducerRecord and an error
* occurs before partition is assigned, then the partition will be set to
* RecordMetadata.UNKNOWN_PARTITION.
* @param exception the exception thrown
*/
@Override
public void onError(ProducerRecord producerRecord, @Nullable RecordMetadata recordMetadata,
Exception exception){
System.out.println("消息发送失败: "+ producerRecord.toString());
}
}

View File

@ -0,0 +1,34 @@
package com.muyu.event.config;
import lombok.NonNull;
import org.apache.kafka.clients.consumer.Consumer;
import org.springframework.kafka.listener.KafkaListenerErrorHandler;
import org.springframework.kafka.listener.ListenerExecutionFailedException;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
@Component
public class MyKafkaListenerErrorHandler implements KafkaListenerErrorHandler {
@Override
@NonNull
public Object handleError(@NonNull Message<?> message,
ListenerExecutionFailedException exception) {
return new Object();
}
@Override
@NonNull
public Object handleError(@NonNull Message<?> message,
@NonNull ListenerExecutionFailedException exception,
Consumer<?, ?> consumer) {
System.out.println("消息详情:"+ message);
System.out.println("异常信息:"+ exception);
System.out.println("消费者详情:" +consumer.groupMetadata());
System.out.println("监听主题:"+ consumer.listTopics());
return KafkaListenerErrorHandler.super.handleError(message, exception, consumer);
}
}

View File

@ -0,0 +1,15 @@
package com.muyu.event.constant;
/**
*
* @author
* @packagecom.muyu.event.constant
* @nameEventConstant
* @date2024/9/28 19:25
*/
public interface EventConstant {
String STORAGE_EVENT = "storageEvent";
}

View File

@ -0,0 +1,31 @@
package com.muyu.event.consumer;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
/**
* kafka
* @author
* @packagecom.muyu.event.consumer
* @nameKafkaConsumer
* @date2024/9/28 23:34
*/
public class KafkaConsumer {
@KafkaListener(topics = "data")
public void dataKafkaConsumer(ConsumerRecord<Object,Object> consumerRecord, Acknowledgment acknowledgment){
Object key = consumerRecord.key();
Object value = consumerRecord.value();
//事件调用
//消息确认消费
acknowledgment.acknowledge();
}
}

View File

@ -0,0 +1,74 @@
package com.muyu.event.controller;
import com.muyu.common.core.domain.Result;
import com.muyu.event.domian.AddCarInformation;
import com.muyu.event.domian.CarInformation;
import com.muyu.event.service.IoTDBService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* iotdbCRUD
* @author
* @packagecom.muyu.event.controller
* @nameItodbController
* @date2024/9/28 19:17
*/
@RestController()
public class IoTDBController {
@Autowired
private IoTDBService tdbService;
/**
*
* @return list
*/
@GetMapping("findIoTDBList")
private Result<List<CarInformation>> findIoTDBList(){
List<CarInformation> list=tdbService.findIoTDBList();
return Result.success(list);
};
/**
* vin
* @param carVin
* @return
*/
@GetMapping("findIoTDBByVin")
public Result<CarInformation> findIoTDBByVin(@RequestParam("carVin") String carVin){
CarInformation carInformation=tdbService.findIoTDBByVin(carVin);
return Result.success(carInformation);
};
/**
*
* @param addCarInformation
* @return
*/
@GetMapping("insertIoTDB")
public Result insertIoTDB(@RequestBody AddCarInformation addCarInformation){
tdbService.insertIoTDB(addCarInformation);
return Result.success("添加成功");
};
}

View File

@ -0,0 +1,28 @@
package com.muyu.event.domian;
import com.muyu.common.core.annotation.Excel;
import lombok.Data;
/**
*
* @author
* @packagecom.muyu.event.domian
* @nameAddCarInformation
* @date2024/9/28 23:10
*/
@Data
public class AddCarInformation {
/**
* vin
*/
@Excel(name = "车辆vin码")
private String carVin;
/**
* vin
*/
@Excel(name = "车辆实时信息")
private String information;
}

View File

@ -0,0 +1,45 @@
package com.muyu.event.domian;
import com.alibaba.fastjson.JSON;
import com.muyu.common.core.annotation.Excel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
* @author
* @packagecom.muyu.event.domian
* @nameCarInformation
* @date2024/9/28 19:25
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CarInformation {
/**
*
*/
@Excel(name = "时间戳")
private Long Time;
/**
* vin
*/
@Excel(name = "车辆vin码")
private String carVin;
/**
*
*/
@Excel(name = "车辆实时信息")
private String information;
}

View File

@ -0,0 +1,42 @@
package com.muyu.event.domian;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.muyu.common.core.annotation.Excel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@TableName("event")
public class Event {
@TableId(value ="event_id" )
@Excel(name = "事件id")
private Integer eventId;
@Excel(name = "事件名称")
private String eventName;
@Excel(name = "车辆vin")
private String carVin;
private String createBy;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}

View File

@ -0,0 +1,28 @@
package com.muyu.event.domian;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
/**
*
* @Author
* @Data 2024/9/29
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class EventActuate {
/**
* json
*/
private String jsonData;
/**
* key
*/
private List<String> eventKeys;
}

View File

@ -0,0 +1,25 @@
package com.muyu.event.eventDispose;
import com.muyu.event.basics.StartEvent;
import com.muyu.event.domian.EventActuate;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* @author
* @package
* @nameAutoStartupEventListener
* @date2024/9/29
*/
@Component
public class AutoStartupEventListener implements ApplicationListener<StartEvent> {
@Override
public void onApplicationEvent(StartEvent event) {
EventActuate eventActuate = event.getEventActuate();
}
}

View File

@ -0,0 +1,37 @@
package com.muyu.event.eventDispose;
import com.muyu.event.basics.EventProcessBasics;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.log4j.Log4j2;
/**
* @author
* @package
* @nameStorageEvent
* @date2024/9/29
*/
@EqualsAndHashCode(callSuper = true)
@Log4j2
@Data
@AllArgsConstructor
public class StorageEvent extends EventProcessBasics {
/**
*
*/
private String eventName;
@Override
public void handleEvent(String eventKey) {
if (eventKey.equals(eventName)){
log.info("开始执行 [{}] 事件", eventKey);
}else if (nextEvent != null){
nextEvent.handleEvent(eventKey);
}else {
log.info("处理结束,最后处理的事件为 [{}]", eventKey);
}
}
}

View File

@ -0,0 +1,22 @@
package com.muyu.event.service;
import com.muyu.event.domian.AddCarInformation;
import com.muyu.event.domian.CarInformation;
import java.util.List;
/**
* @author
* @packagecom.muyu.event.service
* @nameIotdbService
* @date2024/9/28 19:19
*/
public interface IoTDBService {
List<CarInformation> findIoTDBList();
CarInformation findIoTDBByVin(String carVin);
void insertIoTDB(AddCarInformation addCarInformation);
}

View File

@ -0,0 +1,51 @@
package com.muyu.event.service.impl;
import com.muyu.event.config.IoTDBConfig;
import com.muyu.event.domian.AddCarInformation;
import com.muyu.event.domian.CarInformation;
import com.muyu.event.service.IoTDBService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Array;
import java.util.ArrayList;
import java.util.List;
/**
* @author
* @packagecom.muyu.event.service
* @nameIotdbService
* @date2024/9/28 19:19
*/
@Service
public class IoTDBServiceImpl implements IoTDBService {
@Autowired
private IoTDBConfig ioTDBConfig;
@Override
public List<CarInformation> findIoTDBList() {
return null;
}
@Override
public CarInformation findIoTDBByVin(String carVin) {
CarInformation carInformation = ioTDBConfig.queryIoTDB(carVin);
return carInformation;
}
@Override
public void insertIoTDB(AddCarInformation addCarInformation) {
ArrayList<String> list = new ArrayList<>();
if (addCarInformation!=null){
list.add(addCarInformation.getCarVin());
list.add(addCarInformation.getInformation());
}
ioTDBConfig.insertIoTDB(list);
}
}

View File

@ -0,0 +1,66 @@
package com.muyu.event.util;
import org.apache.iotdb.isession.SessionDataSet;
import org.apache.iotdb.isession.util.Version;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.Session;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import java.util.ArrayList;
import java.util.List;
public class Iotdb {
public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException {
System.out.println("测试数据库开始~~~~~");
// 初始化与连接
Session session = new Session.Builder()
.host("47.116.173.119")
.port(6667)
.username("root")
.password("root")
.version(Version.V_1_0)
.build();
// 开启session Rpc不压缩
session.open(false);
// 写入数据
ArrayList<Object> list = new ArrayList<>();
list.add(100);
insertRecord(session,list);
//查询数据
queryRecord(session);
//关闭连接
session.close();
}
private static void insertRecord(Session session, List<Object> values) throws IoTDBConnectionException, StatementExecutionException {
ArrayList<String> measurements = new ArrayList<>();
ArrayList<TSDataType> types = new ArrayList<>();
measurements.add("status");
types.add(TSDataType.INT32);
session.insertRecord("root.four.test",System.currentTimeMillis(),measurements,types,values);
System.out.println("————————————————写入数据成功————————————————");
}
private static void queryRecord(Session session) throws IoTDBConnectionException, StatementExecutionException {
System.out.println("————————————————查询数据开始————————————————");
try(SessionDataSet dataSet= session.executeQueryStatement("select * from root.four.test")){
System.out.println(dataSet.getColumnNames());
dataSet.setFetchSize(1024);
while (dataSet.hasNext()){
System.out.println(dataSet.next());
}
}
System.out.println("————————————————查询数据结束————————————————");
}
}

View File

@ -0,0 +1,53 @@
package com.muyu.event.util;
import org.eclipse.paho.client.mqttv3.*;
public class Receive {
public static void main(String[] args) {
String topic = "vehicle";
String broker = "tcp://47.101.53.251:1883";
String clientId="lw";
try {
MqttClient mqttClient= new MqttClient(broker,clientId);
MqttConnectOptions connectOptions=new MqttConnectOptions();
connectOptions.setCleanSession(true);
System.out.println("Connecting to broker" + broker);
mqttClient.connect(connectOptions);
System.out.println("已连接");
mqttClient.setCallback(new MqttCallback(){
@Override
public void connectionLost(Throwable throwable) {
System.out.println("Connect lost!");
}
@Override
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
System.out.println("Message arrived. topic:"+topic);
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
}
});
mqttClient.subscribe(topic);
System.out.println("Subscribed to topic " + topic);
} catch (MqttException e) {
System.out.println("reason "+e.getReasonCode());
System.out.println("msg " +e.getMessage());
System.out.println("loc " +e.getLocalizedMessage());
System.out.println("cause "+e.getCause());
System.out.println("excep "+e);
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,2 @@
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}

View File

@ -0,0 +1,64 @@
# Tomcat
server:
port: 10003
# nacos线上地址
nacos:
addr: 47.101.53.251:8848
user-name: nacos
password: nacos
namespace: four
# SPRING_AMQP_DESERIALIZATION_TRUST_ALL=true spring.amqp.deserialization.trust.all
# Spring
spring:
iotdb:
amqp:
deserialization:
trust:
all: true
main:
allow-bean-definition-overriding: true
application:
# 应用名称
name: cloud-data
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${nacos.addr}
# nacos用户名
username: ${nacos.user-name}
# nacos密码
password: ${nacos.password}
# 命名空间
namespace: ${nacos.namespace}
config:
# 服务注册地址
server-addr: ${nacos.addr}
# nacos用户名
username: ${nacos.user-name}
# nacos密码
password: ${nacos.password}
# 命名空间
namespace: ${nacos.namespace}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
# 系统共享配置
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# 系统环境Config共享配置
- application-config-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# xxl-job 配置文件
- application-xxl-config-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# rabbit 配置文件
- application-rabbit-config-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
logging:
level:
com.muyu.fence.mapper: DEBUG

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/cloud-data"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/cloud-data"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<property name="log.sky.pattern" value="%d{HH:mm:ss.SSS} %yellow([%tid]) [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 使用gRpc将日志发送到skywalking服务端 -->
<appender name="GRPC_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>${log.sky.pattern}</Pattern>
</layout>
</encoder>
</appender>
<root level="info">
<appender-ref ref="GRPC_LOG"/>
</root>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/cloud-data"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<property name="log.sky.pattern" value="%d{HH:mm:ss.SSS} %yellow([%tid]) [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 使用gRpc将日志发送到skywalking服务端 -->
<appender name="GRPC_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>${log.sky.pattern}</Pattern>
</layout>
</encoder>
</appender>
<root level="info">
<appender-ref ref="GRPC_LOG"/>
</root>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -11,6 +11,10 @@
<artifactId>cloud-modules-vehiclegateway</artifactId>
<description>
cloud-modules-vehiclegateway 车辆网关
</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>

View File

@ -11,6 +11,10 @@
</parent>
<artifactId>cloud-modules-wechat</artifactId>
<description>
cloud-modules-wechat 微信公众号
</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>

View File

@ -23,6 +23,7 @@
<!-- <module>enterprise-operations</module>-->
<module>saas</module>
<module>cloud-modules-vehiclegateway</module>
<module>cloud-event</module>
</modules>
<artifactId>cloud-modules</artifactId>

View File

@ -16,6 +16,10 @@
<module>saas-server</module>
</modules>
<description>
saas 企业业务平台
</description>
<dependencies>
<!--mqtt依赖-->
<dependency>