WebSocket+SpringBoot聊天室(一)

目錄

 

1.項目展示

2.知識要點

3.用戶列表


1.項目展示

具體功能:

進入聊天室之前,需要先輸入用戶名再進入,聊天室中可以進行羣聊,或者點擊用戶列表左邊的CheckBox來制定給某些人發信息,或者一個人實現單聊。每個用戶進入時會顯示“歡迎**進入聊天室”,離開會顯示“恭送**離開聊天室”

項目在我上一篇博文中的項目中進行改進:https://blog.csdn.net/Doctor_LY/article/details/81362718

2.知識要點

在上一篇博文的技術上進行改進,我查看了一些資料,補充了一些知識點,然後再對這個項目進行開發。

  • 一個WebSocket對象就是一個管道,一個管道代表一個session(上面三個客戶端,其實就是有三條連接服務器的管道)
  • 管道與管道之間我是用Session來區分

整體的思路還是比較簡單,上一個項目其實已經實現了羣聊,在基礎上,我們只需要添加的功能是:

  • 用戶列表
  • 用戶進入和離開提示
  • 用戶單聊和多聊

多聊和單聊就是判斷你選擇了那個用戶,獲取該用戶的SessionID,然後在廣播的時候

根據已經獲取的ID,來選擇發送給那些用戶。

3.用戶列表

在登錄界面點擊提交時,我們需要獲取用戶輸入的用戶名。然後傳到聊天室界面,聊天室的頁面js會訪問服務器的WebSocket,此時我們需要把傳過去的用戶名,一起插到訪問WebSocket服務器的URL中。WebScoket服務器再獲取這個用戶名,用來做用戶列表。

登陸頁面HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body style="background:#f5f5f5 url('../img/bg.jpg') no-repeat center;background-size:cover;height: 600px;">
    <form method="post" action="/LoginController" style="text-align: center;margin: 200px 0 0 0">
        <h1>WebSocket聊天室</h1>
        <h2>用戶名:</h2><input placeholder="請輸入聊天時的用戶名" type="text" name="username"
                            style="border-radius: 5px;width: 180px;height: 30px;padding-left: 10px">
        <input class="btn btn-primary" type="submit">
    </form>
</body>
</html>

提交的方法和登陸的方法:

package com.example.websocket.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.util.Map;

@Controller
public class LoginController {

    @PostMapping("/LoginController")
    public ModelAndView login(@RequestParam("username") String username,
                              Map<String,Object> map){
        map.put("username",username);
        return new ModelAndView("chat",map);

    }

    @GetMapping("/login")
    public ModelAndView client(){
        return new ModelAndView("login");
    }
}

可以看到login方法獲取用戶名參數後,轉到chat頁面,因爲這裏用的是FreeMarker模板引擎,在chat頁面中只需要用${username},就可以獲取到用戶名。chat頁面中的js會去訪問Websocket,需要攜帶參數過去。

//判斷當前瀏覽器是否支持WebSocket
    if ('WebSocket' in window) {
        webSocket = new WebSocket('ws://localhost:8080/webSocket?username=' + '${username}');
    } else {
        alert("當前瀏覽器不支持WebSocket");
    }

然後WebSocket需要獲取該參數:

 @OnOpen
    public void onOpen(Session session){
        this.session=session;
        webSockets.add(this);
        //獲取用戶名
        String s=session.getQueryString();
        String urlUsername=s.split("=")[1];
        try {
            username=URLDecoder.decode(urlUsername,"UTF-8");
        }
        catch (Exception e){
            e.printStackTrace();
        }

        //把SessionID和用戶名放進集合裏面
        map.put(session.getId(),username);
        System.out.println("有新的連接,總數"+webSockets.size()+"sessionId:"+session.getId()+" "+username);
        String content="歡迎"+username+"進入聊天室!";
        Message message=new Message(content,map);
        send(message.toJson());
    }
private Session session;
private String username;

private static CopyOnWriteArraySet<WebSocket> webSockets=new CopyOnWriteArraySet<>();
private static Map<String,String> map=new HashMap<>();

因爲在每一個WebSocket對象中,我們添加了兩個屬性,一個username一個session,所以對應每一個通道它都有自己的session和username。我們定義一個Map集合來存儲session和username,這也方便後期用戶離開聊天室去掉該用戶。用戶訪問WebScoket,握手成功後會觸發OnOpen方法,這時候我們就要廣播說,某某同學進入聊天室了。所以就要在OnOpen方法中,廣播了。

在上一個項目中,我們廣播信息是直接用字符串來表示信息,在這個項目中,其實也是用字符串,但是是一個JSON字符串,這樣方便攜帶更多信息,而且規範。我們想一下要廣播的信息包括哪些內容,1、歡迎**進入聊天室。2、還要一個用戶列表,用來及時更新用戶列表

定義一個廣播信息類:

package com.example.websocket.vo;

import com.google.gson.Gson;

import java.text.DateFormat;
import java.util.Date;
import java.util.Map;

public class Message {

    private String content;

    private Map<String,String> names;

    private Date date=new Date();

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }


    public void setContent(String name,String msg) {
        this.content = name+" "+DateFormat.getDateTimeInstance().format(date) +":<br/> "+msg;
    }

    public Map<String, String> getNames() {
        return names;
    }
    public void setNames(Map<String, String> names) {
        this.names = names;
    }


    public String toJson(){
        return gson.toJson(this);
    }

    private static Gson gson=new Gson();

    public Message(String content, Map<String, String> names) {
        this.content = content;
        this.names = names;
    }

    public Message() {
    }
}

    public void setContent(String name,String msg) {
        this.content = name+" "+DateFormat.getDateTimeInstance().format(date) +":<br/> "+msg;
    }

上面這個方法是用來拼裝規範信息的,每一條信息會說明是誰發送過來和具體的時間。

一個對象要轉成JSON字符串就需要用到Gson。在Maven添加相關的依賴。

<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
     <groupId>com.google.code.gson</groupId>
     <artifactId>gson</artifactId>
     <version>2.8.5</version>
</dependency>

把信息拼裝到Message對象中,然後轉成JSON字符串,就可以廣播了。

客戶端在websocket.onmessage方法中接收到字符串和解析JSON字符串

webSocket.onmessage = function (event) {

        $("#userList").html("");
        eval("var msg=" + event.data + ";");

        if (undefined != msg.content)
            setMessageInnerHTML(msg.content);

        if (undefined != msg.names) {
            $.each(msg.names, function (key, value) {
                var htmlstr = '<li>'
                        + '<div class="checkbox checkbox-success checkbox-inline">'
                        + '<input type="checkbox" class="styled" id="'+key+'" value="'+key+'" checked>'
                        + '<label for="'+key+'"></label>'
                        + '</div>'
                        + '<div class="liLeft"><img src="img/2.png"/></div>'
                        + '<div class="liRight">'
                        + '<span class="intername">'+value+'</span>'
                        + '</div>'
                        + '</li>'

                $("#userList").append(htmlstr);
            })
        }
    }

把用戶列表解析出來就得到用戶列表了。

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