vue+django實現一對一聊天功能

vue+django實現一對一聊天和消息推送的功能。主要是通過websocket,由於Django不支持websocket,所以我使用了django-channels。考慮到存儲量的問題,我並沒有把聊天信息存入數據庫,服務端的作用相當於一箇中轉站。我只講述實現功能的結構性代碼,具體的實現還請大家看源代碼。

效果展示

圖片描述

實現過程

後端

首先,我們需要先定義websocket的兩條連接路徑。ws/chat/xxx/xxx指代聊天組)這條路徑是當聊天雙方都進入同一個聊天組以後,開始聊天的路徑。push/xxx/xxx指代用戶名)這條是指當有一方不在聊天組,另一方的消息將通過這條路徑推送給對方。ws/chat/xxx/只有雙方都進入聊天組以後纔開啓,而push/xxx/是自用戶登錄以後,直至退出都開啓的。

websocket_urlpatterns = [
    url(r'^ws/chat/(?P<group_name>[^/]+)/$', consumers.ChatConsumer),
    url(r'^push/(?P<username>[0-9a-z]+)/$', consumers.PushConsumer),
]

我們採用user_a的id加上下劃線_加上user_b的id的方式來命名聊天組名。其中id值從小到大放置,例如:195752_748418。當用戶通過ws/chat/group_name/的方式向服務端請求連接時,後端會把這個聊天組的信息放入一個字典裏。當連接關閉時,就把聊天組從字典裏移除。

class ChatConsumer(AsyncJsonWebsocketConsumer):
    chats = dict()

    async def connect(self):
        self.group_name = self.scope['url_route']['kwargs']['group_name']

        await self.channel_layer.group_add(self.group_name, self.channel_name)
        # 將用戶添加至聊天組信息chats中
        try:
            ChatConsumer.chats[self.group_name].add(self)
        except:
            ChatConsumer.chats[self.group_name] = set([self])

        #print(ChatConsumer.chats)
        # 創建連接時調用
        await self.accept()


    async def disconnect(self, close_code):
        # 連接關閉時調用
        # 將關閉的連接從羣組中移除
        await self.channel_layer.group_discard(self.group_name, self.channel_name)
        # 將該客戶端移除聊天組連接信息
        ChatConsumer.chats[self.group_name].remove(self)
        await self.close()

接着,我們需要判斷連接這個聊天組的用戶個數。當有兩個用戶連接這個聊天組時,我們就直接向這個聊天組發送信息。當只有一個用戶連接這個聊天組時,我們就通過push/xxx/把信息發給接收方。

 async def receive_json(self, message, **kwargs):
        # 收到信息時調用
        to_user = message.get('to_user')
        # 信息發送
        length = len(ChatConsumer.chats[self.group_name])
        if length == 2:
            await self.channel_layer.group_send(
                self.group_name,
                {
                    "type": "chat.message",
                    "message": message.get('message'),
                },
            )
        else:
            await self.channel_layer.group_send(
                to_user,
                {
                    "type": "push.message",
                    "event": {'message': message.get('message'), 'group': self.group_name}
                },
            )


    async def chat_message(self, event):
        # Handles the "chat.message" event when it's sent to us.
        await self.send_json({
            "message": event["message"],
        })


# 推送consumer
class PushConsumer(AsyncWebsocketConsumer):

    async def connect(self):
        self.group_name = self.scope['url_route']['kwargs']['username']

        await self.channel_layer.group_add(
            self.group_name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.group_name,
            self.channel_name
        )

        # print(PushConsumer.chats)

    async def push_message(self, event):
        print(event)
        await self.send(text_data=json.dumps({
            "event": event['event']
        }))

前端

前端實現websocket就比較簡單了。就是對websocket進行初始化,定義當websocket連接、關閉和接收消息時要執行哪些動作。

<script>
  export default {
    name : 'test',
    data() {
      return {
        websock: null,
      }
    },
    created() {
      this.initWebSocket();
    },
    destroyed() {
      this.websock.close() //離開路由之後斷開websocket連接
    },
    methods: {
      initWebSocket(){ //初始化weosocket
        const wsuri = "ws://127.0.0.1:8080";
        this.websock = new WebSocket(wsuri);
        this.websock.onmessage = this.websocketonmessage;
        this.websock.onopen = this.websocketonopen;
        this.websock.onerror = this.websocketonerror;
        this.websock.onclose = this.websocketclose;
      },
      websocketonopen(){ //連接建立之後執行send方法發送數據
        let actions = {"test":"12345"};
        this.websocketsend(JSON.stringify(actions));
      },
      websocketonerror(){//連接建立失敗重連
        this.initWebSocket();
      },
      websocketonmessage(e){ //數據接收
        const redata = JSON.parse(e.data);
      },
      websocketsend(Data){//數據發送
        this.websock.send(Data);
      },
      websocketclose(e){  //關閉
        console.log('斷開連接',e);
      },
    },
  }
</script>

參考文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章