diff --git a/common/pom.xml b/common/pom.xml
new file mode 100644
index 0000000..b43adc5
--- /dev/null
+++ b/common/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ gitlink-notification-system
+ cn.org.gitlink.notification
+ 1.0.0
+
+ gns-common
+ 1.0.0
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 8
+ 8
+
+
+
+
+ [GNS] - Common
+ jar
+ api
+ 4.0.0
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+ 2.3.4.RELEASE
+
+
+ com.alibaba
+ fastjson
+ 1.2.3
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.11.2
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.11.2
+
+
+
+
+ org.springframework.kafka
+ spring-kafka
+ 2.7.6
+
+
+
+
\ No newline at end of file
diff --git a/common/src/main/java/cn/org/gitlink/notification/common/config/RedisConfig.java b/common/src/main/java/cn/org/gitlink/notification/common/config/RedisConfig.java
new file mode 100644
index 0000000..ed9adf4
--- /dev/null
+++ b/common/src/main/java/cn/org/gitlink/notification/common/config/RedisConfig.java
@@ -0,0 +1,44 @@
+package cn.org.gitlink.notification.common.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.*;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * redis配置类
+ * @Date: 2021/09/03
+ * @Author: zengwei
+ * @Description:
+ */
+@Configuration
+public class RedisConfig {
+
+ @Bean
+ @SuppressWarnings("all")
+ public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
+ RedisTemplate template = new RedisTemplate();
+ template.setConnectionFactory(factory);
+ Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+ ObjectMapper om = new ObjectMapper();
+ om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+ om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+ jackson2JsonRedisSerializer.setObjectMapper(om);
+ StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+ // key采用String的序列化方式
+ template.setKeySerializer(stringRedisSerializer);
+ // hash的key也采用String的序列化方式
+ template.setHashKeySerializer(stringRedisSerializer);
+ // value序列化方式采用jackson
+ template.setValueSerializer(jackson2JsonRedisSerializer);
+ // hash的value序列化方式采用jackson
+ template.setHashValueSerializer(jackson2JsonRedisSerializer);
+ template.afterPropertiesSet();
+ return template;
+ }
+}
diff --git a/common/src/main/java/cn/org/gitlink/notification/common/utils/KafkaUtil.java b/common/src/main/java/cn/org/gitlink/notification/common/utils/KafkaUtil.java
new file mode 100644
index 0000000..631ab01
--- /dev/null
+++ b/common/src/main/java/cn/org/gitlink/notification/common/utils/KafkaUtil.java
@@ -0,0 +1,104 @@
+package cn.org.gitlink.notification.common.utils;
+import com.google.common.collect.Lists;
+import org.apache.kafka.clients.admin.*;
+import org.apache.kafka.common.TopicPartitionInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+/**
+ * 操作kafka的工具类
+ *
+ * @author 154594742@qq.com
+ * @date 2021/3/2 14:52
+ */
+
+@Component
+public class KafkaUtil {
+
+ @Value("${spring.kafka.bootstrap-servers:#{null}}")
+ private String springKafkaBootstrapServers;
+
+ private AdminClient adminClient;
+
+ @Autowired
+ private KafkaTemplate kafkaTemplate;
+
+
+ /**
+ * 初始化AdminClient
+ * '@PostConstruct该注解被用来修饰一个非静态的void()方法。
+ * 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。
+ * PostConstruct在构造函数之后执行,init()方法之前执行。
+ */
+ @PostConstruct
+ private void initAdminClient() {
+ Map props = new HashMap<>(1);
+ if (springKafkaBootstrapServers == null) {
+ return;
+ }
+ props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, springKafkaBootstrapServers);
+ adminClient = KafkaAdminClient.create(props);
+ }
+
+ /**
+ * 新增topic,支持批量
+ */
+ public void createTopic(Collection newTopics) {
+ adminClient.createTopics(newTopics);
+ }
+
+ /**
+ * 删除topic,支持批量
+ */
+ public void deleteTopic(Collection topics) {
+ adminClient.deleteTopics(topics);
+ }
+
+ /**
+ * 获取指定topic的信息
+ */
+ public String getTopicInfo(Collection topics) {
+ AtomicReference info = new AtomicReference("");
+ try {
+ adminClient.describeTopics(topics).all().get().forEach((topic, description) -> {
+ for (TopicPartitionInfo partition : description.partitions()) {
+ info.set(info + partition.toString() + "\n");
+ }
+ });
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ return info.get();
+ }
+
+ /**
+ * 获取全部topic
+ */
+ public List getAllTopic() {
+ try {
+ return adminClient.listTopics().listings().get().stream().map(TopicListing::name).collect(Collectors.toList());
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ return Lists.newArrayList();
+ }
+
+ /**
+ * 往topic中发送消息
+ */
+ public void sendMessage(String topic, String message) {
+ kafkaTemplate.send(topic, message);
+ }
+
+}
\ No newline at end of file
diff --git a/common/src/main/java/cn/org/gitlink/notification/common/utils/RedisUtil.java b/common/src/main/java/cn/org/gitlink/notification/common/utils/RedisUtil.java
new file mode 100644
index 0000000..487de15
--- /dev/null
+++ b/common/src/main/java/cn/org/gitlink/notification/common/utils/RedisUtil.java
@@ -0,0 +1,236 @@
+package cn.org.gitlink.notification.common.utils;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+/**
+ * Redis工具类
+ * @author zengwei
+ * @date 2021/09/03
+ */
+@Component
+public class RedisUtil {
+
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+ // =============================common============================
+ /**
+ * 指定缓存失效时间
+ * @param key 键
+ * @param time 时间(秒)
+ * @return
+ */
+ public boolean expire(String key, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.expire(key, time, TimeUnit.SECONDS);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 根据key 获取过期时间
+ * @param key 键 不能为null
+ * @return 时间(秒) 返回0代表为永久有效
+ */
+ public long getExpire(String key) {
+ return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 判断key是否存在
+ * @param key 键
+ * @return true 存在 false不存在
+ */
+ public boolean hasKey(String key) {
+ try {
+ return redisTemplate.hasKey(key);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 删除缓存
+ * @param key 可以传一个值 或多个
+ */
+ @SuppressWarnings("unchecked")
+ public void del(String... key) {
+ if (key != null && key.length > 0) {
+ if (key.length == 1) {
+ redisTemplate.delete(key[0]);
+ } else {
+ redisTemplate.delete(CollectionUtils.arrayToList(key));
+ }
+ }
+ }
+
+ // ============================String=============================
+ /**
+ * 普通缓存获取
+ * @param key 键
+ * @return 值
+ */
+ public Object get(String key) {
+ return key == null ? null : redisTemplate.opsForValue().get(key);
+ }
+
+ /**
+ * 普通缓存放入
+ * @param key 键
+ * @param value 值
+ * @return true成功 false失败
+ */
+ public boolean set(String key, Object value) {
+ try {
+ redisTemplate.opsForValue().set(key, value);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 普通缓存放入并设置时间
+ * @param key 键
+ * @param value 值
+ * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
+ * @return true成功 false 失败
+ */
+ public boolean set(String key, Object value, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+ } else {
+ set(key, value);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ // ================================Map=================================
+ /**
+ * HashGet
+ * @param key 键 不能为null
+ * @param item 项 不能为null
+ * @return 值
+ */
+ public Object hget(String key, String item) {
+ return redisTemplate.opsForHash().get(key, item);
+ }
+
+ /**
+ * 获取hashKey对应的所有键值
+ * @param key 键
+ * @return 对应的多个键值
+ */
+ public Map