header, String jsonBody, String charSet) throws Exception {
+ return doPost(url, map, header, jsonBody,charSet);
+ }
+
+}
diff --git a/hs-im-server/im-common/src/main/java/com/lld/im/common/utils/RouteInfoParseUtil.java b/hs-im-server/im-common/src/main/java/com/lld/im/common/utils/RouteInfoParseUtil.java
new file mode 100644
index 0000000..e99a937
--- /dev/null
+++ b/hs-im-server/im-common/src/main/java/com/lld/im/common/utils/RouteInfoParseUtil.java
@@ -0,0 +1,23 @@
+package com.lld.im.common.utils;
+
+
+import com.lld.im.common.BaseErrorCode;
+import com.lld.im.common.exception.ApplicationException;
+import com.lld.im.common.route.RouteInfo;
+
+/**
+ *
+ * @since JDK 1.8
+ */
+public class RouteInfoParseUtil {
+
+ public static RouteInfo parse(String info){
+ try {
+ String[] serverInfo = info.split(":");
+ RouteInfo routeInfo = new RouteInfo(serverInfo[0], Integer.parseInt(serverInfo[1])) ;
+ return routeInfo ;
+ }catch (Exception e){
+ throw new ApplicationException(BaseErrorCode.PARAMETER_ERROR) ;
+ }
+ }
+}
diff --git a/hs-im-server/im-common/src/main/java/com/lld/im/common/utils/SigAPI.java b/hs-im-server/im-common/src/main/java/com/lld/im/common/utils/SigAPI.java
new file mode 100644
index 0000000..74dad32
--- /dev/null
+++ b/hs-im-server/im-common/src/main/java/com/lld/im/common/utils/SigAPI.java
@@ -0,0 +1,194 @@
+package com.lld.im.common.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+
+/**
+ * @description: app用户 后台管理员
+ *
+ * 10000 xxx 10001 bbbb
+ * @author: lld
+ * @version: 1.0
+ */
+public class SigAPI {
+ final private long appId;
+ final private String key;
+
+ public SigAPI(long appId, String key) {
+ this.appId = appId;
+ this.key = key;
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+ SigAPI asd = new SigAPI(10000, "123456");
+ String sign = asd.genUserSig("lld", 100000000);
+// Thread.sleep(2000L);
+ JSONObject jsonObject = decodeUserSig(sign);
+ System.out.println("sign:" + sign);
+ System.out.println("decoder:" + jsonObject.toString());
+ }
+
+ /**
+ * @description: 解密方法
+ * @param
+ * @return com.alibaba.fastjson.JSONObject
+ * @author lld
+ */
+ public static JSONObject decodeUserSig(String userSig) {
+ JSONObject sigDoc = new JSONObject(true);
+ try {
+ byte[] decodeUrlByte = Base64URL.base64DecodeUrlNotReplace(userSig.getBytes());
+ byte[] decompressByte = decompress(decodeUrlByte);
+ String decodeText = new String(decompressByte, "UTF-8");
+
+ if (StringUtils.isNotBlank(decodeText)) {
+ sigDoc = JSONObject.parseObject(decodeText);
+
+ }
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ return sigDoc;
+ }
+
+ /**
+ * 解压缩
+ *
+ * @param data 待压缩的数据
+ * @return byte[] 解压缩后的数据
+ */
+ public static byte[] decompress(byte[] data) {
+ byte[] output = new byte[0];
+
+ Inflater decompresser = new Inflater();
+ decompresser.reset();
+ decompresser.setInput(data);
+
+ ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);
+ try {
+ byte[] buf = new byte[1024];
+ while (!decompresser.finished()) {
+ int i = decompresser.inflate(buf);
+ o.write(buf, 0, i);
+ }
+ output = o.toByteArray();
+ } catch (Exception e) {
+ output = data;
+ e.printStackTrace();
+ } finally {
+ try {
+ o.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ decompresser.end();
+ return output;
+ }
+
+
+ /**
+ * 【功能说明】用于签发 IM 服务中必须要使用的 UserSig 鉴权票据
+ *
+ * 【参数说明】
+ */
+ public String genUserSig(String userid, long expire) {
+ return genUserSig(userid, expire, null);
+ }
+
+
+ private String hmacsha256(String identifier, long currTime, long expire, String base64Userbuf) {
+ String contentToBeSigned = "TLS.identifier:" + identifier + "\n"
+ + "TLS.appId:" + appId + "\n"
+ + "TLS.expireTime:" + currTime + "\n"
+ + "TLS.expire:" + expire + "\n";
+ if (null != base64Userbuf) {
+ contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
+ }
+ try {
+ byte[] byteKey = key.getBytes(StandardCharsets.UTF_8);
+ Mac hmac = Mac.getInstance("HmacSHA256");
+ SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
+ hmac.init(keySpec);
+ byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes(StandardCharsets.UTF_8));
+ return (Base64.getEncoder().encodeToString(byteSig)).replaceAll("\\s*", "");
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ return "";
+ }
+ }
+
+ private String genUserSig(String userid, long expire, byte[] userbuf) {
+
+ long currTime = System.currentTimeMillis() / 1000;
+
+ JSONObject sigDoc = new JSONObject();
+ sigDoc.put("TLS.identifier", userid);
+ sigDoc.put("TLS.appId", appId);
+ sigDoc.put("TLS.expire", expire);
+ sigDoc.put("TLS.expireTime", currTime);
+
+ String base64UserBuf = null;
+ if (null != userbuf) {
+ base64UserBuf = Base64.getEncoder().encodeToString(userbuf).replaceAll("\\s*", "");
+ sigDoc.put("TLS.userbuf", base64UserBuf);
+ }
+ String sig = hmacsha256(userid, currTime, expire, base64UserBuf);
+ if (sig.length() == 0) {
+ return "";
+ }
+ sigDoc.put("TLS.sig", sig);
+ Deflater compressor = new Deflater();
+ compressor.setInput(sigDoc.toString().getBytes(StandardCharsets.UTF_8));
+ compressor.finish();
+ byte[] compressedBytes = new byte[2048];
+ int compressedBytesLength = compressor.deflate(compressedBytes);
+ compressor.end();
+ return (new String(Base64URL.base64EncodeUrl(Arrays.copyOfRange(compressedBytes,
+ 0, compressedBytesLength)))).replaceAll("\\s*", "");
+ }
+
+ public String genUserSig(String userid, long expire, long time,byte [] userbuf) {
+
+ JSONObject sigDoc = new JSONObject();
+ sigDoc.put("TLS.identifier", userid);
+ sigDoc.put("TLS.appId", appId);
+ sigDoc.put("TLS.expire", expire);
+ sigDoc.put("TLS.expireTime", time);
+
+ String base64UserBuf = null;
+ if (null != userbuf) {
+ base64UserBuf = Base64.getEncoder().encodeToString(userbuf).replaceAll("\\s*", "");
+ sigDoc.put("TLS.userbuf", base64UserBuf);
+ }
+ String sig = hmacsha256(userid, time, expire, base64UserBuf);
+ if (sig.length() == 0) {
+ return "";
+ }
+ sigDoc.put("TLS.sig", sig);
+ Deflater compressor = new Deflater();
+ compressor.setInput(sigDoc.toString().getBytes(StandardCharsets.UTF_8));
+ compressor.finish();
+ byte[] compressedBytes = new byte[2048];
+ int compressedBytesLength = compressor.deflate(compressedBytes);
+ compressor.end();
+ return (new String(Base64URL.base64EncodeUrl(Arrays.copyOfRange(compressedBytes,
+ 0, compressedBytesLength)))).replaceAll("\\s*", "");
+ }
+
+}
\ No newline at end of file
diff --git a/hs-im-server/im-message-store/pom.xml b/hs-im-server/im-message-store/pom.xml
new file mode 100644
index 0000000..0dc2a56
--- /dev/null
+++ b/hs-im-server/im-message-store/pom.xml
@@ -0,0 +1,72 @@
+
+
+ 4.0.0
+
+ com.lld
+ im-system
+ 1.0.0-SNAPSHOT
+
+
+ im-message-store
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+
+ mysql
+ mysql-connector-java
+ runtime
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+ com.github.jeffreyning
+ mybatisplus-plus
+ 1.5.1-RELEASE
+
+
+
+ cn.hutool
+ hutool-all
+
+
+
+
+ com.lld
+ common
+ 1.0.0-SNAPSHOT
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/Application.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/Application.java
new file mode 100644
index 0000000..607c1df
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/Application.java
@@ -0,0 +1,18 @@
+package com.lld.message;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.lld.message.dao.mapper")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+
+}
+
+
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/config/BeanConfig.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/config/BeanConfig.java
new file mode 100644
index 0000000..7fb8692
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/config/BeanConfig.java
@@ -0,0 +1,27 @@
+package com.lld.message.config;
+
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author: Chackylee
+ * @description:
+ **/
+@Configuration
+public class BeanConfig {
+
+ /**
+ * 分页插件
+ */
+ @Bean
+ public PaginationInterceptor paginationInterceptor() {
+ return new PaginationInterceptor();
+ }
+
+ @Bean
+ public EasySqlInjector easySqlInjector () {
+ return new EasySqlInjector();
+ }
+
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/config/EasySqlInjector.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/config/EasySqlInjector.java
new file mode 100644
index 0000000..e6fad30
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/config/EasySqlInjector.java
@@ -0,0 +1,17 @@
+package com.lld.message.config;
+
+import com.baomidou.mybatisplus.core.injector.AbstractMethod;
+import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
+import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
+
+import java.util.List;
+
+public class EasySqlInjector extends DefaultSqlInjector {
+ @Override
+ public List getMethodList(Class> mapperClass) {
+ List methodList = super.getMethodList(mapperClass);
+ methodList.add(new InsertBatchSomeColumn()); // 添加InsertBatchSomeColumn方法
+ return methodList;
+ }
+
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/ImGroupMessageHistoryEntity.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/ImGroupMessageHistoryEntity.java
new file mode 100644
index 0000000..945c5fd
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/ImGroupMessageHistoryEntity.java
@@ -0,0 +1,32 @@
+package com.lld.message.dao;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * @author: Chackylee
+ * @description:
+ **/
+@Data
+@TableName("im_group_message_history")
+public class ImGroupMessageHistoryEntity {
+
+ private Integer appId;
+
+ private String fromId;
+
+ private String groupId;
+
+ /** messageBodyId*/
+ private Long messageKey;
+ /** 序列号*/
+ private Long sequence;
+
+ private String messageRandom;
+
+ private Long messageTime;
+
+ private Long createTime;
+
+
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/ImMessageBodyEntity.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/ImMessageBodyEntity.java
new file mode 100644
index 0000000..1a231ee
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/ImMessageBodyEntity.java
@@ -0,0 +1,32 @@
+package com.lld.message.dao;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * @author: Chackylee
+ * @description:
+ **/
+@Data
+@TableName("im_message_body")
+public class ImMessageBodyEntity {
+
+ private Integer appId;
+
+ /** messageBodyId*/
+ private Long messageKey;
+
+ /** messageBody*/
+ private String messageBody;
+
+ private String securityKey;
+
+ private Long messageTime;
+
+ private Long createTime;
+
+ private String extra;
+
+ private Integer delFlag;
+
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/ImMessageHistoryEntity.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/ImMessageHistoryEntity.java
new file mode 100644
index 0000000..2516e06
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/ImMessageHistoryEntity.java
@@ -0,0 +1,33 @@
+package com.lld.message.dao;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * @author: Chackylee
+ * @description:
+ **/
+@Data
+@TableName("im_message_history")
+public class ImMessageHistoryEntity {
+
+ private Integer appId;
+
+ private String fromId;
+
+ private String toId;
+
+ private String ownerId;
+
+ /** messageBodyId*/
+ private Long messageKey;
+ /** 序列号*/
+ private Long sequence;
+
+ private String messageRandom;
+
+ private Long messageTime;
+
+ private Long createTime;
+
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/mapper/ImGroupMessageHistoryMapper.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/mapper/ImGroupMessageHistoryMapper.java
new file mode 100644
index 0000000..33c7ff2
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/mapper/ImGroupMessageHistoryMapper.java
@@ -0,0 +1,11 @@
+package com.lld.message.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.lld.message.dao.ImGroupMessageHistoryEntity;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ImGroupMessageHistoryMapper extends BaseMapper {
+
+
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/mapper/ImMessageBodyMapper.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/mapper/ImMessageBodyMapper.java
new file mode 100644
index 0000000..26d28e4
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/mapper/ImMessageBodyMapper.java
@@ -0,0 +1,8 @@
+package com.lld.message.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.lld.message.dao.ImMessageBodyEntity;
+import org.springframework.stereotype.Repository;
+@Repository
+public interface ImMessageBodyMapper extends BaseMapper {
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/mapper/ImMessageHistoryMapper.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/mapper/ImMessageHistoryMapper.java
new file mode 100644
index 0000000..82a978a
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/dao/mapper/ImMessageHistoryMapper.java
@@ -0,0 +1,17 @@
+package com.lld.message.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.lld.message.dao.ImMessageHistoryEntity;
+import org.springframework.stereotype.Repository;
+
+import java.util.Collection;
+@Repository
+public interface ImMessageHistoryMapper extends BaseMapper {
+
+ /**
+ * 批量插入(mysql)
+ * @param entityList
+ * @return
+ */
+ Integer insertBatchSomeColumn(Collection entityList);
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/model/DoStoreGroupMessageDto.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/model/DoStoreGroupMessageDto.java
new file mode 100644
index 0000000..12b0bb0
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/model/DoStoreGroupMessageDto.java
@@ -0,0 +1,19 @@
+package com.lld.message.model;
+
+import com.lld.im.common.model.message.GroupChatMessageContent;
+import com.lld.im.common.model.message.MessageContent;
+import com.lld.message.dao.ImMessageBodyEntity;
+import lombok.Data;
+
+/**
+ * @author: Chackylee
+ * @description:
+ **/
+@Data
+public class DoStoreGroupMessageDto {
+
+ private GroupChatMessageContent groupChatMessageContent;
+
+ private ImMessageBodyEntity imMessageBodyEntity;
+
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/model/DoStoreP2PMessageDto.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/model/DoStoreP2PMessageDto.java
new file mode 100644
index 0000000..af8ac0b
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/model/DoStoreP2PMessageDto.java
@@ -0,0 +1,18 @@
+package com.lld.message.model;
+
+import com.lld.im.common.model.message.MessageContent;
+import com.lld.message.dao.ImMessageBodyEntity;
+import lombok.Data;
+
+/**
+ * @author: Chackylee
+ * @description:
+ **/
+@Data
+public class DoStoreP2PMessageDto {
+
+ private MessageContent messageContent;
+
+ private ImMessageBodyEntity imMessageBodyEntity;
+
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/mq/StroeGroupMessageReceiver.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/mq/StroeGroupMessageReceiver.java
new file mode 100644
index 0000000..2404d6e
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/mq/StroeGroupMessageReceiver.java
@@ -0,0 +1,66 @@
+package com.lld.message.mq;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.lld.im.common.constant.Constants;
+import com.lld.message.dao.ImMessageBodyEntity;
+import com.lld.message.model.DoStoreGroupMessageDto;
+import com.lld.message.model.DoStoreP2PMessageDto;
+import com.lld.message.service.StoreMessageService;
+import com.rabbitmq.client.Channel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.Exchange;
+import org.springframework.amqp.rabbit.annotation.Queue;
+import org.springframework.amqp.rabbit.annotation.QueueBinding;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.support.AmqpHeaders;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.messaging.handler.annotation.Headers;
+import org.springframework.messaging.handler.annotation.Payload;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @description:
+ * @author: lld
+ * @version: 1.0
+ */
+@Service
+public class StroeGroupMessageReceiver {
+ private static Logger logger = LoggerFactory.getLogger(StroeGroupMessageReceiver.class);
+
+ @Autowired
+ StoreMessageService storeMessageService;
+
+ @RabbitListener(
+ bindings = @QueueBinding(
+ value = @Queue(value = Constants.RabbitConstants.StoreGroupMessage,durable = "true"),
+ exchange = @Exchange(value = Constants.RabbitConstants.StoreGroupMessage,durable = "true")
+ ),concurrency = "1"
+ )
+ public void onChatMessage(@Payload Message message,
+ @Headers Map headers,
+ Channel channel) throws Exception {
+ String msg = new String(message.getBody(),"utf-8");
+ logger.info("CHAT MSG FORM QUEUE ::: {}", msg);
+ Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
+ try {
+ JSONObject jsonObject = JSON.parseObject(msg);
+ DoStoreGroupMessageDto doStoreGroupMessageDto = jsonObject.toJavaObject(DoStoreGroupMessageDto.class);
+ ImMessageBodyEntity messageBody = jsonObject.getObject("messageBody", ImMessageBodyEntity.class);
+ doStoreGroupMessageDto.setImMessageBodyEntity(messageBody);
+ storeMessageService.doStoreGroupMessage(doStoreGroupMessageDto);
+ channel.basicAck(deliveryTag, false);
+ }catch (Exception e){
+ logger.error("处理消息出现异常:{}", e.getMessage());
+ logger.error("RMQ_CHAT_TRAN_ERROR", e);
+ logger.error("NACK_MSG:{}", msg);
+ //第一个false 表示不批量拒绝,第二个false表示不重回队列
+ channel.basicNack(deliveryTag, false, false);
+ }
+
+ }
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/mq/StroeP2PMessageReceiver.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/mq/StroeP2PMessageReceiver.java
new file mode 100644
index 0000000..0d0b358
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/mq/StroeP2PMessageReceiver.java
@@ -0,0 +1,65 @@
+package com.lld.message.mq;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.lld.im.common.constant.Constants;
+import com.lld.message.dao.ImMessageBodyEntity;
+import com.lld.message.model.DoStoreP2PMessageDto;
+import com.lld.message.service.StoreMessageService;
+import com.rabbitmq.client.Channel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.Exchange;
+import org.springframework.amqp.rabbit.annotation.Queue;
+import org.springframework.amqp.rabbit.annotation.QueueBinding;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.support.AmqpHeaders;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.messaging.handler.annotation.Headers;
+import org.springframework.messaging.handler.annotation.Payload;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @description:
+ * @author: lld
+ * @version: 1.0
+ */
+@Service
+public class StroeP2PMessageReceiver {
+ private static Logger logger = LoggerFactory.getLogger(StroeP2PMessageReceiver.class);
+
+ @Autowired
+ StoreMessageService storeMessageService;
+
+ @RabbitListener(
+ bindings = @QueueBinding(
+ value = @Queue(value = Constants.RabbitConstants.StoreP2PMessage,durable = "true"),
+ exchange = @Exchange(value = Constants.RabbitConstants.StoreP2PMessage,durable = "true")
+ ),concurrency = "1"
+ )
+ public void onChatMessage(@Payload Message message,
+ @Headers Map headers,
+ Channel channel) throws Exception {
+ String msg = new String(message.getBody(),"utf-8");
+ logger.info("CHAT MSG FORM QUEUE ::: {}", msg);
+ Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
+ try {
+ JSONObject jsonObject = JSON.parseObject(msg);
+ DoStoreP2PMessageDto doStoreP2PMessageDto = jsonObject.toJavaObject(DoStoreP2PMessageDto.class);
+ ImMessageBodyEntity messageBody = jsonObject.getObject("messageBody", ImMessageBodyEntity.class);
+ doStoreP2PMessageDto.setImMessageBodyEntity(messageBody);
+ storeMessageService.doStoreP2PMessage(doStoreP2PMessageDto);
+ channel.basicAck(deliveryTag, false);
+ }catch (Exception e){
+ logger.error("处理消息出现异常:{}", e.getMessage());
+ logger.error("RMQ_CHAT_TRAN_ERROR", e);
+ logger.error("NACK_MSG:{}", msg);
+ //第一个false 表示不批量拒绝,第二个false表示不重回队列
+ channel.basicNack(deliveryTag, false, false);
+ }
+
+ }
+}
diff --git a/hs-im-server/im-message-store/src/main/java/com/lld/message/service/StoreMessageService.java b/hs-im-server/im-message-store/src/main/java/com/lld/message/service/StoreMessageService.java
new file mode 100644
index 0000000..58e68d8
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/java/com/lld/message/service/StoreMessageService.java
@@ -0,0 +1,86 @@
+package com.lld.message.service;
+
+import com.lld.im.common.model.message.GroupChatMessageContent;
+import com.lld.im.common.model.message.MessageContent;
+import com.lld.message.dao.ImGroupMessageHistoryEntity;
+import com.lld.message.dao.ImMessageBodyEntity;
+import com.lld.message.dao.ImMessageHistoryEntity;
+import com.lld.message.dao.mapper.ImGroupMessageHistoryMapper;
+import com.lld.message.dao.mapper.ImMessageBodyMapper;
+import com.lld.message.dao.mapper.ImMessageHistoryMapper;
+import com.lld.message.model.DoStoreGroupMessageDto;
+import com.lld.message.model.DoStoreP2PMessageDto;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @description:
+ * @author: lld
+ * @version: 1.0
+ */
+@Service
+public class StoreMessageService {
+
+ @Autowired
+ ImMessageHistoryMapper imMessageHistoryMapper;
+
+ @Autowired
+ ImMessageBodyMapper imMessageBodyMapper;
+
+ @Autowired
+ ImGroupMessageHistoryMapper imGroupMessageHistoryMapper;
+
+
+ @Transactional
+ public void doStoreP2PMessage(DoStoreP2PMessageDto doStoreP2PMessageDto){
+ imMessageBodyMapper.insert(doStoreP2PMessageDto.getImMessageBodyEntity());
+ List imMessageHistoryEntities = extractToP2PMessageHistory(doStoreP2PMessageDto.getMessageContent(), doStoreP2PMessageDto.getImMessageBodyEntity());
+ imMessageHistoryMapper.insertBatchSomeColumn(imMessageHistoryEntities);
+ }
+
+
+ public List extractToP2PMessageHistory(MessageContent messageContent,
+ ImMessageBodyEntity imMessageBodyEntity){
+ List list = new ArrayList<>();
+ ImMessageHistoryEntity fromHistory = new ImMessageHistoryEntity();
+ BeanUtils.copyProperties(messageContent,fromHistory);
+ fromHistory.setOwnerId(messageContent.getFromId());
+ fromHistory.setMessageKey(imMessageBodyEntity.getMessageKey());
+ fromHistory.setCreateTime(System.currentTimeMillis());
+ fromHistory.setSequence(messageContent.getMessageSequence());
+
+ ImMessageHistoryEntity toHistory = new ImMessageHistoryEntity();
+ BeanUtils.copyProperties(messageContent,toHistory);
+ toHistory.setOwnerId(messageContent.getToId());
+ toHistory.setMessageKey(imMessageBodyEntity.getMessageKey());
+ toHistory.setCreateTime(System.currentTimeMillis());
+ toHistory.setSequence(messageContent.getMessageSequence());
+
+ list.add(fromHistory);
+ list.add(toHistory);
+ return list;
+ }
+
+ @Transactional
+ public void doStoreGroupMessage(DoStoreGroupMessageDto doStoreGroupMessageDto) {
+ imMessageBodyMapper.insert(doStoreGroupMessageDto.getImMessageBodyEntity());
+ ImGroupMessageHistoryEntity imGroupMessageHistoryEntity = extractToGroupMessageHistory(doStoreGroupMessageDto.getGroupChatMessageContent(),doStoreGroupMessageDto.getImMessageBodyEntity());
+ imGroupMessageHistoryMapper.insert(imGroupMessageHistoryEntity);
+
+ }
+
+ private ImGroupMessageHistoryEntity extractToGroupMessageHistory(GroupChatMessageContent
+ messageContent , ImMessageBodyEntity messageBodyEntity){
+ ImGroupMessageHistoryEntity result = new ImGroupMessageHistoryEntity();
+ BeanUtils.copyProperties(messageContent,result);
+ result.setGroupId(messageContent.getGroupId());
+ result.setMessageKey(messageBodyEntity.getMessageKey());
+ result.setCreateTime(System.currentTimeMillis());
+ return result;
+ }
+}
diff --git a/hs-im-server/im-message-store/src/main/resources/application.yml b/hs-im-server/im-message-store/src/main/resources/application.yml
new file mode 100644
index 0000000..e6f9b0f
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/resources/application.yml
@@ -0,0 +1,63 @@
+spring:
+ profiles:
+ active: dev
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ password: beAs0LHX2GyTxMw4
+ url: jdbc:mysql://192.168.2.201:3306/im-core?serverTimezone=UTC&useSSL=false&characterEncoding=UTF8
+ username: root
+
+ redis:
+ host: 43.139.191.204
+ port: 6379
+ database: 8
+ jedis:
+ pool:
+ max-active: 100
+ max-idle: 100
+ max-wait: 1000
+ min-idle: 10
+ password: dSMIXBQrCBXiHHjk123
+ rabbitmq:
+ host: 192.168.2.180
+ port: 5672
+ addresses: 192.168.2.180
+ username: guest
+ password: guest
+ # virtual-host:
+ listener:
+ simple:
+ concurrency: 5
+ max-concurrency: 10
+ acknowledge-mode: MANUAL
+ prefetch: 1
+ publisher-confirms: true
+ publisher-returns: true
+ template:
+ mandatory: true
+ cache:
+ connection:
+ mode: channel
+ channel:
+ size: 36
+ checkout-timeout: 0
+
+
+
+# logger 配置
+logging:
+ config: classpath:logback-spring.xml
+
+
+mybatis-plus:
+
+ configuration:
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+ mapper-locations: classpath*:mapper/*.xml
+ global-config:
+ db-config:
+ update-strategy: NOT_EMPTY
+
+#mybatis:
+# configuration:
+# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
diff --git a/hs-im-server/im-message-store/src/main/resources/logback-spring.xml b/hs-im-server/im-message-store/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..b9cd630
--- /dev/null
+++ b/hs-im-server/im-message-store/src/main/resources/logback-spring.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DEBUG
+
+
+ ${CONSOLE_LOG_PATTERN}
+ utf8
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ ${logFile}.%d{yyyy-MM-dd}.log
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss} -%msg%n
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ ${logFile}.%d{yyyy-MM-dd}.log
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss} -%msg%n
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hs-im-server/im-service/pom.xml b/hs-im-server/im-service/pom.xml
index 637de92..805ad60 100644
--- a/hs-im-server/im-service/pom.xml
+++ b/hs-im-server/im-service/pom.xml
@@ -18,26 +18,26 @@
-
-
-
-
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
org.springframework.boot
spring-boot-starter-validation
-
-
-
-
+
+ com.github.sgroschupf
+ zkclient
+
-
-
-
-
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
@@ -45,11 +45,11 @@
spring-boot-starter-web
-
-
-
-
-
+
+ com.lld
+ im-codec
+ 1.0.0-SNAPSHOT
+
@@ -87,6 +87,12 @@
common
1.0.0-SNAPSHOT
+
+ com.lld
+ im-system
+ 1.0.0-SNAPSHOT
+ compile
+
@@ -98,4 +104,4 @@
-
\ No newline at end of file
+
diff --git a/hs-im-server/im-service/src/main/java/com/lld/im/service/Application.java b/hs-im-server/im-service/src/main/java/com/lld/im/service/Application.java
index 272d021..30df89a 100644
--- a/hs-im-server/im-service/src/main/java/com/lld/im/service/Application.java
+++ b/hs-im-server/im-service/src/main/java/com/lld/im/service/Application.java
@@ -4,8 +4,10 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-@SpringBootApplication
+@SpringBootApplication(scanBasePackages = {"com.lld.im.service",
+ "com.lld.im.common"})
@MapperScan("com.lld.im.service.*.dao.mapper")
+//导入用户资料,删除用户资料,修改用户资料,查询用户资料
public class Application {
public static void main(String[] args) {
@@ -17,4 +19,3 @@ public class Application {
-
diff --git a/hs-im-server/im-service/src/main/java/com/lld/im/service/config/BeanConfig.java b/hs-im-server/im-service/src/main/java/com/lld/im/service/config/BeanConfig.java
index c07d827..2e671a5 100644
--- a/hs-im-server/im-service/src/main/java/com/lld/im/service/config/BeanConfig.java
+++ b/hs-im-server/im-service/src/main/java/com/lld/im/service/config/BeanConfig.java
@@ -1,7 +1,22 @@
package com.lld.im.service.config;
+import com.lld.im.common.config.AppConfig;
+import com.lld.im.common.enums.ImUrlRouteWayEnum;
+import com.lld.im.common.enums.RouteHashMethodEnum;
+import com.lld.im.common.route.RouteHandle;
+import com.lld.im.common.route.algorithm.consistenthash.AbstractConsistentHash;
+import com.lld.im.common.route.algorithm.consistenthash.ConsistentHashHandle;
+import com.lld.im.common.route.algorithm.consistenthash.TreeMapConsistentHash;
+import com.lld.im.common.route.algorithm.loop.LoopHandle;
+import com.lld.im.common.route.algorithm.random.RandomHandle;
+import com.lld.im.service.utils.SnowflakeIdWorker;
+import org.I0Itec.zkclient.ZkClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import java.lang.reflect.Method;
+
/**
* @description:
* @author: lld
@@ -10,4 +25,50 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
+ @Autowired
+ AppConfig appConfig;
+
+ @Bean
+ public ZkClient buildZKClient() {
+ return new ZkClient(appConfig.getZkAddr(),
+ appConfig.getZkConnectTimeOut());
+ }
+
+ @Bean
+ public RouteHandle routeHandle() throws Exception {
+
+ Integer imRouteWay = appConfig.getImRouteWay();
+ String routWay = "";
+
+ ImUrlRouteWayEnum handler = ImUrlRouteWayEnum.getHandler(imRouteWay);
+ routWay = handler.getClazz();
+
+ RouteHandle routeHandle = (RouteHandle) Class.forName(routWay).newInstance();
+ if(handler == ImUrlRouteWayEnum.HASH){
+
+ Method setHash = Class.forName(routWay).getMethod("setHash", AbstractConsistentHash.class);
+ Integer consistentHashWay = appConfig.getConsistentHashWay();
+ String hashWay = "";
+
+ RouteHashMethodEnum hashHandler = RouteHashMethodEnum.getHandler(consistentHashWay);
+ hashWay = hashHandler.getClazz();
+ AbstractConsistentHash consistentHash
+ = (AbstractConsistentHash) Class.forName(hashWay).newInstance();
+ setHash.invoke(routeHandle,consistentHash);
+ }
+
+ return routeHandle;
+ }
+
+ @Bean
+ public EasySqlInjector easySqlInjector () {
+ return new EasySqlInjector();
+ }
+
+ @Bean
+ public SnowflakeIdWorker buildSnowflakeSeq() throws Exception {
+ return new SnowflakeIdWorker(0);
+ }
+
+
}
diff --git a/hs-im-server/im-service/src/main/java/com/lld/im/service/config/EasySqlInjector.java b/hs-im-server/im-service/src/main/java/com/lld/im/service/config/EasySqlInjector.java
new file mode 100644
index 0000000..b512cab
--- /dev/null
+++ b/hs-im-server/im-service/src/main/java/com/lld/im/service/config/EasySqlInjector.java
@@ -0,0 +1,17 @@
+package com.lld.im.service.config;
+
+import com.baomidou.mybatisplus.core.injector.AbstractMethod;
+import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
+import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
+
+import java.util.List;
+
+public class EasySqlInjector extends DefaultSqlInjector {
+ @Override
+ public List getMethodList(Class> mapperClass) {
+ List methodList = super.getMethodList(mapperClass);
+ methodList.add(new InsertBatchSomeColumn()); // 添加InsertBatchSomeColumn方法
+ return methodList;
+ }
+
+}
diff --git a/hs-im-server/im-service/src/main/java/com/lld/im/service/config/RedisConfig.java b/hs-im-server/im-service/src/main/java/com/lld/im/service/config/RedisConfig.java
new file mode 100644
index 0000000..8426754
--- /dev/null
+++ b/hs-im-server/im-service/src/main/java/com/lld/im/service/config/RedisConfig.java
@@ -0,0 +1,48 @@
+package com.lld.im.service.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * @author: Chackylee
+ * @description:
+ **/
+@Configuration
+public class RedisConfig {
+
+ @Autowired
+ RedisConnectionFactory redisConnectionFactory;
+
+ @Bean
+ public RedisTemplate