一、ER设计
涉及两个库:crm、base,其中crm里2张表(consumer、consumer_wx_info);base里3张表(chat_apply_record、chat_friend_role、chat_msg_record)
图:
详细表结构:
consumer ---- 主要存用户注册信息
CREATE TABLE `consumer` (
`c_id` int NOT NULL AUTO_INCREMENT COMMENT 'cid',
`w_code` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '账号',
`name` varchar(25) DEFAULT NULL COMMENT '姓名',
`avatar_url` varchar(255) DEFAULT NULL COMMENT '头像',
`sex` varchar(5) DEFAULT NULL COMMENT '性别',
`birth` date DEFAULT NULL COMMENT '生日',
`email` varchar(30) DEFAULT NULL COMMENT '邮箱',
`phone` varchar(11) DEFAULT NULL COMMENT '手机',
`address` varchar(255) DEFAULT NULL COMMENT '地址',
`status` tinyint DEFAULT '1' COMMENT '状态',
`w_code_update_time` date DEFAULT NULL COMMENT 'wCode更改时间',
`create_time` datetime NOT NULL COMMENT '创建时间',
`create_by` varchar(25) NOT NULL COMMENT '创建人',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`update_by` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人',
`dr` tinyint NOT NULL DEFAULT '0' COMMENT '删除',
PRIMARY KEY (`c_id`),
UNIQUE KEY `cid_cus_index` (`c_id`) USING BTREE,
UNIQUE KEY `cus_wxCode_index` (`w_code`) USING BTREE,
UNIQUE KEY `cus_phone_index` (`phone`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
consumer_wx_info --主要存用户微信相关信息,从微信获取到的openid、用户信息等
CREATE TABLE `consumer_wx_info` (
`u_id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`c_id` int DEFAULT NULL COMMENT 'cid',
`nick_name` varchar(50) DEFAULT NULL COMMENT '昵称',
`avatar_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '头像',
`openid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'openid',
`unionid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'unionid',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`dr` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除状态',
PRIMARY KEY (`u_id`) USING BTREE,
UNIQUE KEY `openid_index` (`openid`) USING BTREE COMMENT 'openid索引',
KEY `cid_key` (`c_id`),
CONSTRAINT `cid_key` FOREIGN KEY (`c_id`) REFERENCES `consumer` (`c_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
chat_apply_record -- 好友申请记录表,主要存好友申请记录
CREATE TABLE `chat_apply_record` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`apply_c_id` int NOT NULL COMMENT '申请人',
`receive_c_id` int NOT NULL COMMENT '接收人',
`info` text COMMENT '备注信息',
`apply_status` int NOT NULL DEFAULT '0' COMMENT '是否同意(0-待审核,1-已同意,2-已过期)',
`apply_time` datetime DEFAULT NULL COMMENT '同意时间',
`create_time` datetime NOT NULL COMMENT '申请时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `cpr_applyId_receive_index` (`apply_c_id`,`receive_c_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
chat_friend_role -- 好友关系联系表
CREATE TABLE `chat_friend_role` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`c_id_a` int NOT NULL COMMENT '申请人用户ID',
`remark_a` varchar(25) DEFAULT NULL COMMENT '申请人备注',
`c_id_b` int NOT NULL COMMENT '接收人用户ID',
`remark_b` varchar(25) DEFAULT NULL COMMENT '接收人备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '申请加为好友时间',
`dr` int NOT NULL DEFAULT '0' COMMENT '删除',
PRIMARY KEY (`id`),
UNIQUE KEY `cfr_cid_index` (`c_id_a`,`c_id_b`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
chat_msg_record --聊天记录表,主要存聊天信息
CREATE TABLE `chat_msg_record` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
`s_c_id` int NOT NULL COMMENT '发送用户ID',
`r_c_id` int NOT NULL COMMENT '接收用户ID',
`type` varchar(10) NOT NULL COMMENT '消息类型',
`content` text COMMENT '内容',
`voice_length` int DEFAULT NULL COMMENT '语音时间长度',
`send_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '发送时间',
`dr` int NOT NULL DEFAULT '0' COMMENT '删除',
`read` int NOT NULL DEFAULT '0' COMMENT '已读',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
然后还有一个存储过程以及函数方法,两者都放在base库里面
存储过程用来使好友申请记录过期,函数是用来获取用户名称首字母
存储过程 -- expire_apply_record
CREATE DEFINER=`root`@`%` PROCEDURE `expire_apply_record`(
IN p_datetime DATETIME,
OUT p_status TINYINT,
OUT p_cost_time VARCHAR(20),
OUT p_msg VARCHAR(100),
OUT p_exception VARCHAR(2000))
BEGIN
DECLARE p_state_msg VARCHAR(255) DEFAULT 'N/A';
DECLARE p_error_msg1 VARCHAR(255);
DECLARE p_error_msg2 VARCHAR(255);
DECLARE p_begin_time DATETIME;
-- SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1 p_error_msg1 = RETURNED_SQLSTATE, p_error_msg2 = MESSAGE_TEXT;
SET p_status = FALSE;
SET p_exception = CONCAT('执行异常,在【',p_state_msg,'】出错,详细:',p_error_msg1, ' : ', p_error_msg2);
END;
SET p_status = TRUE;
SET p_begin_time = CURRENT_TIMESTAMP(3);
-- NEXTWORK
UPDATE base.chat_apply_record
SET apply_status = 2
WHERE
create_time < SUBDATE( now( ), INTERVAL 7 DAY );
SET p_msg = CONCAT('本次总共更新:',ROW_COUNT(),'条数据');
SET p_cost_time = TIMEDIFF(CURRENT_TIMESTAMP(3), p_begin_time);
END
2个函数:
FIRSTLETTER
CREATE DEFINER=`root`@`%` FUNCTION `FIRSTLETTER`(P_NAME VARCHAR(255)) RETURNS varchar(255) CHARSET utf8mb3
BEGIN
DECLARE V_RETURN VARCHAR(255);
DECLARE V_FIRST_CHAR VARCHAR(255);
#这块主要意思是假如传入的是英文串的话,只取首字母
set V_FIRST_CHAR =UPPER(LEFT(CONVERT(P_NAME USING gbk),1));
set V_RETURN = V_FIRST_CHAR;
#如果是这些特殊符号,直接返回#
IF V_FIRST_CHAR in ('(',')','《','》','1','2','3','4','5','6','7','8','9','0','*','+','-','=','/','\\','{','}','[',']','(',')','(',')')
THEN SET V_RETURN = '#';
#两个不相等只有一个情况,V_FIRST_CHAR是中文汉字或者中文符号。
elseif LENGTH( V_FIRST_CHAR) <> CHARACTER_LENGTH( V_FIRST_CHAR )
then
SET V_RETURN = ELT(INTERVAL(CONV(HEX(left(CONVERT(P_NAME USING gbk),1)),16,10),
0xB0A1,0xB0C5,0xB2C1,0xB4EE,0xB6EA,0xB7A2,0xB8C1,0xB9FE,0xBBF7,
0xBFA6,0xC0AC,0xC2E8,0xC4C3,0xC5B6,0xC5BE,0xC6DA,0xC8BB,
0xC8F6,0xCBFA,0xCDDA,0xCEF4,0xD1B9,0xD4D1),
'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P','Q','R','S','T','W','X','Y','Z');
#如果是下面的直接原样输出
elseif V_FIRST_CHAR in ('A','B','C','D','E','F','G','H','J','K','L','M','N','O','P','Q','R','S','T','W','X','Y','Z')
then SET V_RETURN = V_RETURN;
#其他的输出#
else
SET V_RETURN = '#';
END IF;
#为空的话输出#
RETURN IFNULL(V_RETURN,'#');
END
PINYIN
CREATE DEFINER=`root`@`%` FUNCTION `PINYIN`(P_NAME VARCHAR(255)) RETURNS varchar(255) CHARSET utf8mb4
BEGIN
DECLARE V_COMPARE VARCHAR(255);
DECLARE V_RETURN VARCHAR(255);
DECLARE I INT;
SET I = 1;
SET V_RETURN = '';
#循环截取字符
while I < LENGTH(P_NAME) do
SET V_COMPARE = SUBSTR(P_NAME, I, 1);
IF (V_COMPARE != '') THEN
#字符串拼接
SET V_RETURN = CONCAT(V_RETURN, base.FIRSTLETTER(V_COMPARE));
END IF;
SET I = I + 1;
end while;
IF (ISNULL(V_RETURN) or V_RETURN = '') THEN
SET V_RETURN = P_NAME;
END IF;
RETURN V_RETURN;
END
数据库全部准备完毕 。。。。。。。。。。。
二、后端代码块
后端代码主要就三大功能组 --- 用户、消息、系统
主要讲解消息系统,其他模块代码已上传 ,可自行查看
在消息系统中我们为了保证消息的实时性需要使用websocket实现实时通信,而mq的作用就相当于消息队列,为了让消息准确发送,所以接下来注重讲解消息通过mq消息队列通知websocket发送实时消息
一、mq消息队列模块
主要两大功能块-- 消费者、生产者;生产者是在发送消息时,把消息放入mq消息队列,消费者是在用户进入系统后连接上websocket后进行消费消息;
生产者模块这儿我们主要使用顺序队列消息,主要是为了保证消息发送的顺序性,然后按照消息发送的时间按序发送给在线用户
消费者主要是实现一个监听作用
下面是整个MQ代码结构,包含4个方法,生产者、消费者、配置、枚举类(定义topic)
MQConsumer -- 提供消费者消费方法,也算是一个配置类
package com.wm.mq;
import lombok.extern.log4j.Log4j2;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Log4j2
@Component
public class MQConsumer {
@Value("${rocketMqConfig.groupName}") //组名
private String groupName;
@Value("${rocketMqConfig.nameSrvAddr}") //mqserver地址
private String nameSrvAddr;
public DefaultMQPushConsumer consumer(MQTopic mqTopic) {
try {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer();
consumer.setConsumerGroup(groupName);
consumer.setNamesrvAddr(nameSrvAddr);
consumer.subscribe(mqTopic.topic,mqTopic.tags);
consumer.setMessageModel(MessageModel.CLUSTERING);
return consumer; //上面是配置项,然后返回一个consumer容器,在需要消费时可直接使用该容器的一些消费方法
} catch (MQClientException e) {
log.error(e);
}
return null;
}
}
MQProducer -- 提供生产消息方法,本系统就只用到其中的顺序消息
package com.wm.mq;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Log4j2
@Component
public class MQProducer {
private DefaultMQProducer defaultMQProducer;
@Resource
public void setDefaultMQProducer(DefaultMQProducer defaultMQProducer