SpringBoot chat message persistence
Single chat – realize the function
- Sending text messages
- Chat list
- Chat Message Details
By integrating Netty-Socketio with SpringBoot, the client can send messages to the server, and the server can receive them normally
The received messages are stored persistently, mysql database is used for data storage, and Mybatis operates database
If you don’t know anything about databases, look at this
MySql met
MySql advanced
Chat message list storage
Create message record column table table
CREATE TABLE `t_message_record` (
`msg_id` bigint(20) NOT NULL COMMENT 'the message Id'.`send_id` bigint(20) NOT NULL COMMENT 'Sender Id'.`receive_id` bigint(20) NOT NULL COMMENT 'Recipient Id'.`type` char(1) NOT NULL COMMENT 'Message type'.`chat_type` char(1) NOT NULL COMMENT 'Type of chat'.`content` varchar(500) NOT NULL COMMENT 'Chat content'.`send_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Message sent time'.`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation time'.`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update Time',
PRIMARY KEY (`msg_id`))ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Message log Sheet';
Copy the code
Write MessageRecordMapper operation database
/ * * *@author taohua
*/
@Mapper
public interface MessageRecordMapper {
/** * single chat * <p> * Insert a single chat message **@paramMessageRecordDO Message entity *@returnSucceeded in adding */
int insertMessageRecord(MessageRecordDO messageRecordDO);
}
Copy the code
Write the MessageRecordMapper XML mapping file
<! DOCTYPEmapper PUBLIC "- / / mybatis.org//DTD Mapper / 3.0 / EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.moose.operator.mapper.MessageRecordMapper">
<insert id="insertMessageRecord"
parameterType="com.moose.operator.model.domain.message.MessageRecordDO">
INSERT INTO `t_message_record` (msg_id, send_id, receive_id, type, chat_type, content)
VALUES (#{msgId}, #{sendId}, #{receiveId}, #{type}, #{chatType}, #{content})
</insert>
</mapper>
Copy the code
Used in SingleMessageServiceImpl
saveMessage
The main logic
@Resource
private SocketConnection socketConnection;
/ / injection MessageRecordMapper
@Resource
private MessageRecordMapper messageRecordMapper;
@Override public void saveMessage(MessageTemplate template) {
// TODO: message ack
MessageRecordDO messageRecord = null;
try {
// mock
//String fromUserId = template.getFromUserId();
//SocketIOClient fromSocket = socketIOClientMap.get(fromUserId);
//if ("786600935907659776".equals(toUserId)) {
// if (null != fromSocket && fromSocket.isChannelOpen()) {
// fromsocket. sendEvent(chatconstant. SINGLE_CHAT, "you are not friends!!") );
/ /}
// return;
/ /}
//log.info("{}", request);
// Check message template parameters...
// Check whether the user exists...
// Whether a friend...
/////////////////////////// save message record ///////////////////////////
// Sender ID
Long sendId = template.getSendId();
// Recipient ID
Long receiveId = template.getReceiveId();
// Build the message
messageRecord = new MessageRecordDO();
messageRecord.setMsgId(snowflakeIdWorker.nextId());
messageRecord.setSendId(sendId);
messageRecord.setReceiveId(receiveId);
messageRecord.setContent(template.getContent());
messageRecord.setType(MessageUtils.diffMessageType(template.getType()));
messageRecord.setChatType(MessageUtils.diffChatType(template.getChatType()));
// Save the message
messageRecordMapper.insertMessageRecord(messageRecord);
} catch (Exception exception) {
exception.printStackTrace();
log.info("Message parsing: Error [{}] message [{}]", exception.getMessage(), template); }}Copy the code
Service unit test cases
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class SingleMessageServiceTest {
@Resource
private SingleMessageService singleMessageService;
@Test
public void testSaveMessage(a) {
MessageTemplate template = new MessageTemplate();
mockJiangJing(template);
mockTaohua(template);
mockWangZhaoJun(template);
}
private void mockWangZhaoJun(MessageTemplate template) {
/ / wang zhaojun
template.setSendId(775113183131074560L);
/ / jiang jing
template.setReceiveId(775113183131074580L);
template.setType("MS:TEXT");
template.setChatType("CT:SINGLE");
template.setContent("Hello, Jiang Jing, I'm Wang Zhaojun.");
singleMessageService.saveMessage(template);
}
private void mockTaohua(MessageTemplate template) {
/ / the peach blossom
template.setSendId(786600935907659776L);
/ / wang zhaojun
template.setReceiveId(775113183131074560L);
template.setType("MS:TEXT");
template.setChatType("CT:SINGLE");
template.setContent("Hello, Wang Zhaojun, I am peach blossom.");
singleMessageService.saveMessage(template);
}
private void mockJiangJing(MessageTemplate template) {
/ / jiang jing
template.setSendId(775113183131074580L);
/ / the peach blossom
template.setReceiveId(786600935907659776L);
template.setType("MS:TEXT");
template.setChatType("CT:SINGLE");
template.setContent("Hello, peach blossom, I am river view.");
singleMessageService.saveMessage(template);
/ / wang zhaojun
template.setReceiveId(775113183131074560L);
template.setType("MS:TEXT");
template.setChatType("CT:SINGLE");
template.setContent("Hello, Wang Zhaojun, I am Jiang Jing."); singleMessageService.saveMessage(template); }}Copy the code
Single chat implementation
- Save the message before sending it?
- from
socketConnection
To obtain, need to determine when online - Send messages using SocketIOClient sendEvent
code
// TODO:Failure of message transfer process
// TODO:The concurrent situation
// Send a message
// Check whether it is online
SocketIOClient receiveSocket = socketConnection.getSocketIOClient(String.valueOf(receiveId));
if (null! = receiveSocket && receiveSocket.isChannelOpen()) {// The client listens for chat events
receiveSocket.sendEvent(ChatConstant.SINGLE_CHAT, MapperUtils.obj2json(template));
// TODO: un read count compute --> 0
// messageRecord.setUnReadCount(0);
} else {
// TODO: un read count compute --> redis increment or decrement
// messageRecord.setUnReadCount(0);
}
Copy the code
debugging
Socket_io_client is used for debugging. Dart language module, behind the integration of Flutter convenience
Please refer to gitee.com/shizidada/d…
Implementation effect
Long connection, received data can be rendered on the UI
Get chat list
MessageRecordMapper Java Adds a query method
/** * Chat list **@paramUserId Current user *@returnChat list */
List<MessageRecordDO> selectMessageRecordList(Long userId);
/** * Query chat list details **@paramSendId Sender Id *@paramReceiveId Recipient Id *@returnChat details */
List<MessageRecordDO> selectChatMessageList(@Param("sendId") Long sendId,
@Param("receiveId") Long receiveId);
Copy the code
MessageRecordMapper XML Adds a query mapping
<select id="selectMessageRecordList" resultMap="BaseResultMap"><! [CDATA[ SELECT t.* FROM ( SELECT msg_id, send_id, receive_id, type, chat_type, content, send_time FROM ( SELECT receive_id AS receiver, msg_id, send_id, receive_id, type, chat_type, content, send_time FROM t_message_record WHERE send_id = #{userId} AND receive_id <> #{userId} UNION SELECT send_id AS receiver, msg_id, send_id, receive_id, type, chat_type, content, send_time FROM t_message_record WHERE send_id <> #{userId} AND receive_id = #{userId} ORDER BY send_time DESC ) AS newTable GROUP BY receiver ORDER BY send_time DESC ) AS t ]]></select>
<select id="selectChatMessageList" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column"/>
FROM
t_message_record
WHERE
( send_id = #{sendId} AND receive_id = #{receiveId} )
OR
( send_id = #{receiveId} AND receive_id = #{sendId} )
ORDER BY send_time ASC
</select>
Copy the code
Unit testing
@Test
public void testSelectMessageRecordList(a) {
/ / jiang jing
Long userId = 775113183131074580L;
List<MessageRecordDO> messageRecordDOS = messageRecordMapper.selectMessageRecordList(userId);
log.info("{}", messageRecordDOS);
}
Copy the code
Write the interface
Get the chat list service MessageRecordService
public interface MessageRecordService {
/** * Get the list of chat messages **@return List<ChatMessageRecord>
*/
List<MessageRecordDO> listMessageRecord(a);
/** * Query the chat list **@paramUserId Peer Id *@paramPageNum page *@returnChat list details */
List<MessageRecordDO> listMessageChat(Long userId, Integer pageNum);
}
Copy the code
The service implementation is MessageRecordServiceImpl
@Slf4j
@Service
public class MessageRecordServiceImpl implements MessageRecordService {
@Resource
private UserInfoService userInfoService;
@Resource
private MessageRecordMapper messageRecordMapper;
@Override public List<MessageRecordDO> listMessageRecord(a) {
Long userId = userInfoService.getCurrentUserId();
return messageRecordMapper.selectMessageRecordList(userId);
}
@Override public List<MessageRecordDO> listMessageChat(Long userId, Integer pageNum) {
Long currentUserId = userInfoService.getCurrentUserId();
PageHelper.startPage(pageNum, 10);
returnmessageRecordMapper.selectChatMessageList(currentUserId, userId); }}Copy the code
PageHelper performs paging queries and queries only 10 items of data at a time based on paging
PageHelper.startPage(pageNum, 10);
Message interface MessageController
@RestController
@RequestMapping("/api/v1/message")
public class MessageController {
@Resource
private MessageRecordService messageRecordService;
/** * Gets the chat list of the currently logged in user **@returnR<? > Chat list */
@PostMapping(value = "/record/list")
publicR<? > getChatMessageList() {return R.ok(messageRecordService.listMessageRecord());
}
/** * get Id **@returnR<? < span style = "max-width: 100%; clear: both; min-height: 1em
@PostMapping(value = "/chat/list")
publicR<? > getMessageChatList(@RequestParam("chatId") Long chatId,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum
) {
returnR.ok(messageRecordService.listMessageChat(chatId, pageNum)); }}Copy the code
Enabling service access
Gets the chat history listhttp://localhost:7000/api/v1/message/record/list
Gets the chat history listhttp://localhost:7000/api/v1/message/chat/list
TODO for
- Group chat, sending binary messages (picture messages, video messages…)
- Check the message template parameters
- Check whether the user exists
- Are you friends?
- Active push? Again, pull the list of messages
- Message storage
read
Diffusion,write
The spread of - In the distributed case, message push
- .
Pay attention to the public account “full stack technology Department”, continue to learn more interesting technical knowledge.