SpringBoot+WebSocket實如今線聊天(二)

本文是vhr系列第15篇,項目地址:https://github.com/lenve/vhr 前端

在線聊天使用了SpringBoot+WebSocket實現,爲了保證用戶隱私,全部的聊天數據都保存在系統本地,服務器只進行了數據轉發。OK,那接下來,咱們來看下大體的實現步驟。ios

服務端

服務端首先加入websocket依賴,以下:git

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

建立WebSocket的配置類,以下:github

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry.addEndpoint("/ws/endpointChat").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/queue","/topic");
    }
}

這裏我並未使用原生的websocket協議,而是使用了websocket的子協議stomp,方便一些。消息代理既使用了/queue,又使用了/topic,主要是由於我這裏既有點對點的單聊(queue),也有發送系統消息的羣聊(topic)。 web

建立websocket處理類Controller,以下:spring

@Controller
public class WsController {
    @Autowired
    SimpMessagingTemplate messagingTemplate;

    @MessageMapping("/ws/chat")
    public void handleChat(Principal principal, String msg) {
        String destUser = msg.substring(msg.lastIndexOf(";") + 1, msg.length());
        String message = msg.substring(0, msg.lastIndexOf(";"));
        messagingTemplate.convertAndSendToUser(destUser, "/queue/chat", new ChatResp(message, principal.getName()));
    }
}

消息協議很簡單:發送來的消息,最後一個;後面跟的是該條消息要發送到哪一個用戶,這裏經過字符串截取將之提取出來。響應消息包含兩個字段,一個是消息內容,一個是該條消息由誰發送。 數據庫

OK,如此以後,咱們的服務端就寫好了,很簡單。編程

前端

前端代碼稍微複雜,我這裏主要和小夥伴介紹下個人大體思路和核心代碼,具體代碼小夥伴能夠star源碼進行研究。 json

首先,當用戶登陸成功以後,我就發起websocket的鏈接,將ws鏈接起來,ws的代碼我主要寫在了store中,以下:axios

connect(context){
    context.state.stomp = Stomp.over(new SockJS("/ws/endpointChat"));
    context.state.stomp.connect({}, frame=> {
    context.state.stomp.subscribe("/user/queue/chat", message=> {
        var msg = JSON.parse(message.body);
        var oldMsg = window.localStorage.getItem(context.state.user.username + "#" + msg.from);
        if (oldMsg == null) {
        oldMsg = [];
        oldMsg.push(msg);
        window.localStorage.setItem(context.state.user.username + "#" + msg.from, JSON.stringify(oldMsg))
        } else {
        var oldMsgJson = JSON.parse(oldMsg);
        oldMsgJson.push(msg);
        window.localStorage.setItem(context.state.user.username + "#" + msg.from, JSON.stringify(oldMsgJson))
        }
        if (msg.from != context.state.currentFriend.username) {
        context.commit("addValue2DotMap", "isDot#" + context.state.user.username + "#" + msg.from);
        }
        //更新msgList
        var oldMsg2 = window.localStorage.getItem(context.state.user.username + "#" + context.state.currentFriend.username);
        if (oldMsg2 == null) {
        context.commit('updateMsgList', []);
        } else {
        context.commit('updateMsgList', JSON.parse(oldMsg2));
        }
    });
    }, failedMsg=> {

    });
}

鏈接成功以後,就能夠準備接收服務端的消息了,接收到服務端的消息後,數據保存在localStorage中,保存格式是 當前用戶名#消息發送方用戶名:[{from:'消息發送方',msg:'消息內容'}],注意後面的是一個json數組,整個存儲的key之因此用當前用戶名#消息發送方用戶名是爲了不同一個瀏覽器多個用戶登陸所產生的數據紊亂,OK,這樣兩我的的聊天記錄都將保存在這個數組中。在聊天展現頁面,當數組中的數據發生變化時,自動更新。

在聊天頁面,經過stomp發送消息,以下:

this.$store.state.stomp.send("/ws/chat", {}, this.msg + ";" + this.currentFriend.username);

注意每條消息的內容除了內容自己外,還要加上當前發送者的名字。
每次發送成功後更新聊天頁面便可。更新聊天頁面代碼以下:

<template v-for="msg in msgList">
<!--發送來的消息-->
<div
    style="display: flex;justify-content: flex-start;align-items: center;box-sizing: border-box;"
    v-if="msg.from==currentFriend.username">
    <img :src="currentFriend.userface" class="userfaceImg">
    <div
    style="display: inline-flex;border-style: solid;border-width: 1px;border-color: #20a0ff;border-radius: 5px;padding: 5px 8px 5px 8px">
    {{msg.msg}}
    </div>
</div>
<!--發出去的消息-->
<div v-if="msg.from!=currentFriend.username"
        style="display: flex;justify-content: flex-end;align-items: center;box-sizing: border-box;">
    <div
    style="display: inline-flex;border-style: solid;border-width: 1px;border-color: #20a0ff;border-radius: 5px;padding: 5px 8px 5px 8px;margin-right: 3px;background-color: #9eea6a">
    {{msg.msg}}
    </div>
    <img :src="currentUser.userface" class="userfaceImg">
</div>
</template>

若是消息中的from字段的值,就是當前聊天的用戶名,則是發送來的消息,不然就是發出去的消息,不一樣的消息設置不一樣的樣式便可。

核心代碼基本如此,可是瑣碎的細節實際上是比較多的,小夥伴能夠star源碼進行研究。

本系列其餘文章:

1.SpringBoot+Vue先後端分離,使用SpringSecurity完美處理權限問題(一)
2.SpringBoot+Vue先後端分離,使用SpringSecurity完美處理權限問題(二)
3.SpringSecurity中密碼加鹽與SpringBoot中異常統一處理
4.axios請求封裝和異常統一處理
5.權限管理模塊中動態加載Vue組件
6.SpringBoot+Vue先後端分離,使用SpringSecurity完美處理權限問題(六)
7.vhr部門管理數據庫設計與編程
8.使用MyBatis輕鬆實現遞歸查詢與存儲過程調用
9.ElementUI中tree控件踩坑記
10.SpringBoot中自定義參數綁定
11.SpringBoot中使用POI,快速實現Excel導入導出
12.SpringBoot中發送QQ郵件
13.SpringBoot中使用Freemarker構建郵件模板
14.SpringBoot+WebSocket實如今線聊天(一)

關注公衆號,能夠及時接收到最新文章:

圖片描述

相關文章
相關標籤/搜索