springboot 整合 websocket實現在線聊天和消息通知

一、內容一覽

本文由下文改進而來:https://blog.csdn.net/qq_41463655/article/details/92410518

適合做簡易聊天室,多聊天室,發送接收消息可添加分組id
適合做及時消息通知

聊天頁面,比較簡陋

在這裏插入圖片描述

另外提供 WebSocketController web接口

API一覽

在這裏插入圖片描述

發送消息/通知接口API

在這裏插入圖片描述

代碼結構

在這裏插入圖片描述

二、代碼部分

1、添加maven 依賴

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

2、dto 創建 SendMsgDTO

package com.ws.ldy.common.websocket.model.dto;

import com.ws.ldy.base.convert.Convert;
import lombok.Data;


/***
 * TODO  websocket客服端-發送消息-入參參數
 * @author 王松
 * @mail [email protected]
 * @date 2020/6/30 0030 18:24
 */
@Data
public class SendMsgDTO extends Convert {
    /**
     * 接收人用戶Id (目標ID,逗號分隔) (所有人使用-ALL)
     */
    private String to;
    /**
     * 發送內容
     */
    private String content;

    /**
     * @param to      接收人用戶Id (目標ID,逗號分隔) (所有人使用-ALL)
     * @param content 發送內容
     */
    public SendMsgDTO(String to, String content) {
        this.to = to;
        this.content = content;
    }

    public SendMsgDTO() {
    }
}

3、entity/ 創建 OnlineUser

package com.ws.ldy.common.websocket.model.entity;

import com.ws.ldy.base.convert.Convert;
import com.ws.ldy.common.utils.LocalDateTimeUtils;
import lombok.AllArgsConstructor;
import lombok.Data;

import javax.websocket.Session;
import java.time.LocalDateTime;

/***
 * TODO  當前在線列表信息
 * @author 王松
 * @mail [email protected]
 * @date 2020/7/1 0001 11:58 
 */
@Data
@AllArgsConstructor
public class OnlineUser extends Convert {
    /**
     * 用戶ID
     */
    private String userId;
    /**
     * 用戶名稱
     */
    private String username;
    /**
     * 用戶會話 (使用該對象進行消息發送)
     */
    private Session session;
    /**
     * 連接時間
     */
    private String createTime;

    /**
     * @param userId   用戶id
     * @param username 用戶名稱
     * @param session  用戶session 回話信息
     */
    public OnlineUser(String userId, String username, Session session) {
        this.userId = userId;
        this.username = username;
        this.session = session;
        this.createTime = LocalDateTimeUtils.parse(LocalDateTime.now());
    }
}

4、vo/ 創建 OnlineUserVO

package com.ws.ldy.common.websocket.model.vo;

import com.ws.ldy.base.convert.Convert;
import lombok.Data;

/**
 * TODO  在線列表信息返回
 */
@Data
public class OnlineUserVO extends Convert {

    /**
     * 用戶ID
     */
    private String userId;
    /**
     * 用戶名稱
     */
    private String username;
    /**
     * 連接時間
     */
    private String createTime;
}

5、vo/ 創建 SendMsgVO (發送消息的所有內容)

package com.ws.ldy.common.websocket.model.vo;

import com.ws.ldy.base.convert.Convert;
import com.ws.ldy.common.websocket.service.impl.WebsocketServiceImpl;
import com.ws.ldy.common.utils.LocalDateTimeUtils;
import lombok.Data;

import java.time.LocalDateTime;


/**
 * TODO  websocket客戶端-接收端-返回參數
 *
 * @author 王松
 * @mail [email protected]
 * @date 2020/6/30 0030 18:24
 */
@Data
public class SendMsgVO extends Convert {
    /**
     * 消息類型(1-上線通知 2-下線通知 3-在線名單通知  4-代表普通消息通知 )
     */
    private Integer mesType;
    /**
     * 發送人用戶Id(來源Id,上線爲上線線人的用戶Id)
     */
    private String from;
    /**
     * 發送人用戶名( 上下線爲上線線人的用戶名)
     */
    private String username;
    /**
     * 接收人用戶Id (目標ID,逗號分隔) (所有人使用-ALL,包括自己在內也能接收)
     */
    private String to;
    /**
     * 發送內容
     */
    private String content;
    /**
     * 擴展消息字段(json)
     */
    private String extras;
    /**
     * 當前在線人數
     */
    private Integer onlineNum;
    /**
     * 消息創建時間(YYYY-MM-DD )
     */
    private String createTime;

//    /**
//     * 消息類型,int類型(0:text、1:image、2:voice、3:vedio、4:music、5:news)
//     */
//    private Integer msgType;


    /**
     * @param mesType  消息類型(1-上線通知 2-下線通知 3-在線名單通知  4-代表普通消息通知 )
     * @param from     發送人Id(來源Id),上下線爲上線人的用戶id
     * @param username 發送人姓名username,上下線爲上線人的用戶名
     * @param to       接收人Id(目標ID,逗號分隔,所有人使用-ALL)
     * @param content  發送消息內容
     * @param extras   發送消息擴展字段
     */
    public SendMsgVO(Integer mesType, String from, String username, String to, String content, String extras) {
        this.mesType = mesType;
        this.from = from;
        this.username = username;
        this.to = to;
        this.content = content;
        this.extras = extras;
        this.onlineNum = WebsocketServiceImpl.onlineNumber.intValue();
        this.createTime = LocalDateTimeUtils.parse(LocalDateTime.now());
    }
}

6、WebsocketService 接口

package com.ws.ldy.common.websocket.service;

import com.ws.ldy.common.websocket.model.vo.OnlineUserVO;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import java.util.List;

/**
 * TODO websocket 監聽類(連接,斷點,消息發送等)
 * <p>
 * /websocket/{userId}/{username}   =  /websocket/用戶Id/用戶名 來連接websocket,該參數會帶到每一個監聽方法中
 * </P>
 */
public interface WebsocketService {


    //================================================================================
    //================================================================================
    //===============================  監聽方法 =======================================
    //================================================================================
    //================================================================================

    /**
     * TODO  監聽連接(有用戶連接,立馬到來執行這個方法),session 發生變化
     *
     * @param userId   用戶id
     * @param username 用戶名
     * @param session  當前用戶會話
     * @return void
     * @date 2020/6/30 0030 9:28
     */
    public void onOpen(@PathParam("userId") String userId, @PathParam("username") String username, Session session);


    /**
     * TODO  監聽斷開連接(有用戶退出,會立馬到來執行這個方法)
     *
     * @param userId   用戶id
     * @param username 用戶名
     * @param session  當前用戶會話
     */
    public void onClose(@PathParam("userId") String userId, @PathParam("username") String username, Session session);


    /**
     * TODO 異常停止
     *
     * @param userId   用戶id
     * @param username 用戶名
     * @param session  當前用戶會話
     * @param error    異常信息
     */
    public void onError(@PathParam("userId") String userId, @PathParam("username") String username, Session session, Throwable error);

    /**
     * TODO 監聽消息發送(收到客戶端的消息立即執行)
     *
     * @param userId   用戶id
     * @param username 用戶名
     * @param message  傳遞的消息內容, json數據( to=接收人用戶Id  (目標ID,逗號分隔) || content=內容)
     * @param session  當前用戶會話
     *
     *                 <p>
     *                 // 前端發送內容格式
     *                 ....
     *                 // 拼接參數
     *                 let message = { "content": content, "to": to };
     *                 // 發送數據
     *                 webSocket.send(JSON.stringify(message));
     *                 ....
     *                 </P>
     */
    public void onMessage(@PathParam("userId") String userId, @PathParam("username") String username, String message, Session session);



    //================================================================================
    //================================================================================
    //=======================  service方法(http接口調用操作) ============================
    //================================================================================
    //================================================================================

    /**
     * 獲取當前在線人數
     *
     * @return
     */
    public Integer getOnlineCount();


    /**
     * 獲取當前在線用戶列表
     *
     * @return
     */
    public List<OnlineUserVO> getOnlineUsersList();

    /**
     * 發送消息
     *
     * @param form     發送人id
     * @param username 發送人用戶名
     * @param to       接收人id(多個逗號分隔)
     * @param content  發送內容
     * @param extras  擴暫發送內容
     * @return
     */
    public List<OnlineUserVO> send(String form, String username, String to, String content, String extras);
}



7、WebsocketServiceImpl 接口實現( 重點)

package com.ws.ldy.common.websocket.service.impl;

import com.alibaba.fastjson.JSON;
import com.ws.ldy.common.utils.JsonUtils;
import com.ws.ldy.common.websocket.model.dto.SendMsgDTO;
import com.ws.ldy.common.websocket.model.entity.OnlineUser;
import com.ws.ldy.common.websocket.model.vo.OnlineUserVO;
import com.ws.ldy.common.websocket.model.vo.SendMsgVO;
import com.ws.ldy.common.websocket.service.WebsocketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * TODO websocket 監聽類(連接,斷點,消息發送等)
 * <p>
 * /websocket/{userId}/{username}   =  /websocket/用戶Id/用戶名 來連接websocket,該參數會帶到每一個監聽方法中
 * </P>
 *
 * @ServerEndpoint: socket鏈接地址
 */
@ServerEndpoint("/websocket/{userId}/{username}")
@Service
@Slf4j
public class WebsocketServiceImpl implements WebsocketService {
    /**
     * 在線人數  //使用原子類AtomicInteger, --->  static併發會產生線程安全問題,    //public  static Integer onlineNumber = 0;
     */
    public static AtomicInteger onlineNumber = new AtomicInteger(0);
    /**
     * 所有用戶信息(session + userId + username + createTime  --> 以用戶的id爲key, 通過用戶key來獲取用戶session進行消息發送)
     */
    public static Map<String, OnlineUser> clients = new ConcurrentHashMap<>();

    //================================================================================
    //================================================================================
    //===============================  監聽方法 =======================================
    //================================================================================
    //================================================================================

    /**
     * TODO  監聽連接(有用戶連接,立馬到來執行這個方法),session 發生變化
     */
    @OnOpen
    public void onOpen(@PathParam("userId") String userId, @PathParam("username") String username, Session session) {
        // 自增1
        onlineNumber.getAndIncrement();
        // 保存新用戶id,用戶名,session會話,登錄時間
        clients.put(userId, new OnlineUser(userId, username, session));

        // 告訴所有人,我上線了
        String content = "系統消息:" + username + " 上線了";
        this.send(new SendMsgVO(1, userId, username, "ALL", content, null));

        // 給自己發一條消息:告訴自己現在都有誰在線
        this.send(new SendMsgVO(3, userId, username, userId, JSON.toJSONString(getOnlineUsers()), null));
        log.info("有新連接加入!sessionId:{} userId:{} userName:{} 當前在線人數:{}", session.getId(), userId, username, onlineNumber);
    }


    /**
     * TODO  監聽斷開連接(有用戶退出,會立馬到來執行這個方法)
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId, @PathParam("username") String username, Session session) {
        // 自減1
        onlineNumber.getAndDecrement();
        // 所有在線用戶中去除下線用戶
        clients.remove(userId);
        // 告訴所有人,我下線了
        String content = "系統消息:" + username + " 下線了";
        this.send(new SendMsgVO(2, userId, username, "ALL", content, null));
        // 日誌
        log.info(username + ":已離線! 當前在線人數" + onlineNumber);
    }

    /**
     * TODO 異常停止
     */
    @OnError
    public void onError(@PathParam("userId") String userId, @PathParam("username") String username, Session session, Throwable error) {
        error.printStackTrace();
        log.info("服務端發生了錯誤" + error.getMessage());
    }

    /**
     * TODO 監聽消息發送(收到客戶端的消息立即執行)
     */
    @OnMessage
    public void onMessage(@PathParam("userId") String userId, @PathParam("username") String username, String message, Session session) {
        log.info("服務器接收到發送消息請求,發送人id={},用戶名={}, 接收發送消息={}", userId, username, message);
        // 請求參數(接收人+發送內容)
        SendMsgDTO sendMsgDTO = JsonUtils.parseEntity(message, SendMsgDTO.class);
        // 發送消息
        this.send(new SendMsgVO(4, userId, username, sendMsgDTO.getTo(), sendMsgDTO.getContent(), null));
    }


    /**
     * 消息發送( 遍歷用戶Id , 在通過sendMsg方法發送消息)
     *
     * @param sendMsg:消息內容
     */
    private void send(SendMsgVO sendMsg) {
        if ("ALL".equals(sendMsg.getTo()) || "all".equals(sendMsg.getTo())) {
            // 發送消息給所有人
            Set<String> userIds = clients.keySet();
            for (String userId : userIds) {
                this.sendMsg(userId, sendMsg);
            }
        } else {
            //發送消息給指定人
            String[] userIds = sendMsg.getTo().split(",");
            for (String userId : userIds) {
                this.sendMsg(userId, sendMsg);
            }
        }
    }


    /**
     * 消息發送(最後發送, 在send方法中循環用戶Id 列表依次發送消息給指定人)
     * <p>
     * // 消息發送(同步:getBasicRemote 異步:getAsyncRemote)
     * </P>
     *
     * @param userId  消息接收人ID , onlineUsers 的 key
     * @param sendMsg 消息內容
     */
    private void sendMsg(String userId, SendMsgVO sendMsg) {
        // 判斷用戶是否在線, 在線發送消息推送
        if (clients.containsKey(userId)) {
            try {
                clients.get(userId).getSession().getBasicRemote().sendText(JSON.toJSONString(sendMsg));
            } catch (IOException e) {
                e.printStackTrace();
                log.info(userId, sendMsg.getUsername() + "上線的時候通知所有人發生了錯誤");
            }
        }
    }

    /**
     * 獲取當前在線列表
     * <p>
     * 獲取當前在線列表, 把onlineUsers 轉到 OnlineUsersVO返回
     * </p>
     *
     * @return
     */
    public synchronized List<OnlineUserVO> getOnlineUsers() {
        List<OnlineUserVO> onlineUsersVOList = new ArrayList<>();
        for (OnlineUser onlineUsers : clients.values()) {
            onlineUsersVOList.add(onlineUsers.convert(OnlineUserVO.class));
        }
        return onlineUsersVOList;
    }


    //================================================================================
    //================================================================================
    //=======================  service方法(http接口調用操作) ============================
    //================================================================================
    //================================================================================


    /**
     * 獲取當前在線人數
     *
     * @return
     */
    public Integer getOnlineCount() {
        return onlineNumber.get();
    }


    /**
     * 獲取當前在線用戶信息
     *
     * @return
     */
    public List<OnlineUserVO> getOnlineUsersList() {
        return getOnlineUsers();
    }

    /**
     * 發送消息 (單向通知發送,不可回覆)
     *
     * @param form     發送人id
     * @param username 發送人用戶名
     * @param to       接收人id(多個逗號分隔)
     * @param content  發送內容
     * @param content  發送內容
     * @param content  擴暫發送內容
     * @return
     */
    public List<OnlineUserVO> send(String form, String username, String to, String content, String extras) {
        // 發送消息
        this.send(new SendMsgVO(4, form, username, to, content, extras));
        return getOnlineUsers();
    }
}

8、WebsocketController web-Api 接口方法

package com.ws.ldy.base.controller;

import com.ws.ldy.common.result.Result;
import com.ws.ldy.common.result.ResultEnum;
import com.ws.ldy.common.websocket.model.vo.OnlineUserVO;
import com.ws.ldy.common.websocket.service.WebsocketService;
import com.ws.ldy.config.error.ErrorException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * websocket類
 *
 * @ServerEndpoint: socket鏈接地址
 */
@Api(value = "WebSocketController", tags = "websocket 相關通知/聊天")
@RequestMapping("/websocket")
@RestController
@Slf4j
public class WebSocketController {

    /**
     * websocket ip 或域名
     */
    @Value("${websocket.ip}")
    private String ip;

    /**
     * websocket 端口號
     */
    @Value("${websocket.port}")
    private String port;

    /**
     * websocket接口
     */
    @Value("${websocket.interfaceName}")
    private String interfaceName;


    /**
     * TODO 獲取webSocket  連接地址,  // 實際情況根據用戶 token獲取用戶信息返回
     * 獲取socket地址
     * 獲取用戶名
     * 獲取用戶Id
     */
    @RequestMapping(value = "/getPath", method = RequestMethod.GET)
    @ApiOperation("遊客登錄獲取websocket連接地址")
    public Result<Map<String, String>> getPath() {
        // 配置檢查
        if (StringUtils.isBlank(ip) || StringUtils.isBlank(port) || StringUtils.isBlank(interfaceName)) {
            throw new ErrorException(ResultEnum.SYS_SOCKET_CONFIG_ERROR);
        }
        // 隨機用戶名
        String username = "遊客:" + new SimpleDateFormat("ssSSS").format(new Date());
        // 隨機用戶id
        String userId = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());

        // 連接地址, // "ws://192.168.0.154:9049/websocket/1/張三"
        String path = "ws://" + ip + ":" + port + interfaceName + "/" + userId + "/" + username;
        log.info("websocket請求地址:" + path);

        //返回參數
        Map<String, String> map = new HashMap<>();
        map.put("path", path);
        map.put("userId", userId);
        map.put("username", username);
        return Result.success(map);
    }

    // websocket 邏輯代碼
    @Autowired
    private WebsocketService websocketService;

    /**
     * TODO 發送消息
     */
    @RequestMapping(value = "/send", method = RequestMethod.POST)
    @ApiOperation("發送消息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "form", value = "發送人Id", required = true),
            @ApiImplicitParam(name = "username", value = "發送人用戶名", required = true),
            @ApiImplicitParam(name = "to", value = "接收人Id, 全部爲ALL", required = true),
            @ApiImplicitParam(name = "content", value = "發送內容", required = true),
            @ApiImplicitParam(name = "extras", value = "附加發送內容", required = true)
    })
    public Result<Void> send(String form, String username, String to, String content, String extras) {
        websocketService.send(form, username, to, content, extras);
        return Result.success();
    }

    /**
     * TODO 獲取當前在線人數
     */
    @RequestMapping(value = "/getOnlineCount", method = RequestMethod.GET)
    @ApiOperation("發送消息")
    public Result<Integer> getOnlineCount() {
        Integer onlineCount = websocketService.getOnlineCount();
        return Result.success(onlineCount);
    }


    @RequestMapping(value = "/getOnlineUsersList", method = RequestMethod.GET)
    @ApiOperation("獲取當前在線用戶列表")
    public Result<List<OnlineUserVO>> getOnlineUsersList() {
        return Result.success(websocketService.getOnlineUsersList());
    }
}


9、yml 創建websocket配置

## websocket 配置
websocket:
  # websocket 服務器部署地址的ip或者域名 --> 本地可以使用127.0.0.1 || localhost
  ip: 127.0.0.1
  # websocket 服務器端口,獲取當前服務器端口
  port: ${server.port}
  # websocket 連接接口, WebsocketServiceImpl的 @ServerEndpoint 內參數
  interfaceName: /websocket

10、最後別忘了 WebSocketConfig 配置


/**
  * TODO  WebSocket 配置類
  * @author 王松
  * @mail  [email protected]
  * @date  2020/6/30 0030 9:26
  */
@Configuration
public class WebSocketConfig {

    /**
     * 服務器節點
     * <p>
     * 如果使用獨立的servlet容器,而不是直接使用springboot的內置容器,就不要注入ServerEndpointExporter,因爲它將由容器自己提供和管理
     *
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

11、前端頁面html

<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    <title>websocket</title>
    <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js"></script>
    <script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
    <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
    <script th:src="@{/js/app.js}"></script>
</head>
<css>

</css>
<style>
    /* overflow-y :auto;overflow :auto;  寬高自適應滾動條 */
    /* 羣聊*/
    .quLiao {
        width: 80%;
        height: 300px;
        background-color: papayawhip;
        float: left;
        overflow-y: auto;
        overflow: auto;
    }

    /* 私聊*/
    .siLiao {
        width: 80%;
        height: 300px;
        background-color: papayawhip;
        float: left;
        overflow-y: auto;
        overflow: auto;
    }

    /*在線列表*/
    .zxList {
        width: 20%;
        background-color: #F2F2F2;
        float: left;
        overflow-y: auto;
        overflow: auto;
    }
</style>
<body>
<br>


<span class="quLiao" id="quLiao">
    <li style="text-align: center">羣聊信息</li> <!--    <li style="text-align: right">靠右</li>  <li style="text-align: left" >靠左</li>-->
</span>


<span class="zxList" id="zxList">
    <li style="text-align: center">在線列表</li>
</span>


<!-- 消息輸入框 -->
<textarea id="text" placeholder="請輸入內容-發送消息[Ctrl+回車鍵]" rows="3%" cols="60%"></textarea>
<td>消息發送至:</td>
<select id="to" size="1" style="width: 10%;height:30px">
    <option value="ALL">所有人</option> <!-- ALL 爲所有人 -->
</select>
<input onclick="send()" type="button" value="發送">

<div class="siLiao" id="siLiao">
    <li style="text-align: center">私聊信息</li>  <!--    <li style="text-align: right">靠右</li>  <li style="text-align: left" >靠左</li>-->
</div>
<br>
<br>

<!-- ===============================================================================  -->

</body>
<script type="text/javascript">

    // 獲取socket連接地址,連接地址url中自帶登錄用戶的賬號信息,前端無需關心
    let JsonData = ajaxGet(path + "/websocket/getPath");
    //
    let socketPath = JsonData.data.path;   //連接地址
    let formUserId = JsonData.data.userId;     //用戶Id
    let formUsername = JsonData.data.username; //用戶名

    let zxList = $("#zxList");  //在線列表
    let quLiao = $("#quLiao");  //羣聊
    let siLiao = $("#siLiao");  //私聊
    let toList = $("#to");      //消息接收人select選擇框

    let webSocket;
    // var commWebSocket;
    http:
        if ("WebSocket" in window) {

            // 連接地址:後端獲取
            websocket = new WebSocket(socketPath);   // 如: "ws://192.168.0.154:9049/websocket/張三/1"

            // 連通成功的監聽
            websocket.onopen = function () {
                quLiao.html(quLiao.html() + " <li style='text-align: center'>系統消息:[登陸成功]</li>")
            };

            // 接收後臺服務端的消息監聽
            websocket.onmessage = function (evt) {
                let received_msg = evt.data;           // 接收到的數據
                let obj = JSON.parse(received_msg);    // json數據
                let mesType = obj.mesType;             // 數據類型(1上線/2下線/3在線名單/4發信息)
                let from = obj.from;                   // 來源Id,上下線時爲上下線的用戶id
                let username = obj.username;           // 來源用戶,上下線時爲上下線的用戶名
                let to = obj.to;                       // 目標Id(接收人用戶Id,逗號分隔,所有人時爲-ALL))
                let content = obj.content;             // 內容
                let extras = obj.extras;               // 擴展內容(json)
                let onlineNum = obj.onlineNum;         // 在線人數
                let createTime = obj.createTime;       // 消息時間
                //alert(JSON.stringify(received_msg));

                // 上線通知+在線列表刷新
                if (mesType === 1) {
                    // 羣聊信息時上線
                    quLiao.html(quLiao.html() + " <li style='text-align: center;color: #00FF00'>" + content + " </li>");
                    // 在線列表(id=用戶id,用於下線刪除)
                    zxList.html(zxList.html() + " <li id='" + from + "' style='text-align: left'>---" + username + "&nbsp;&nbsp;&nbsp;&nbsp;" + createTime + "</li>");
                    // 在線人選擇框(optionId爲了下線通知移除)
                    toList.html(toList.html() + "<option id='option" + from + "' value='" + from + "'>" + username + "</option> ")
                }

                // 下線通知+在線列表刷新
                else if (mesType === 2) {
                    // 羣聊信息暫時下線
                    quLiao.html(quLiao.html() + " <li style='text-align: center;color: red'>" + content + " </li>");
                    // 在線列表刪除下線人
                    $("#" + from).remove();
                    // 在線人選擇框移除下線人
                    $("#option" + from).remove();
                }

                // 在線列表通知(自己登錄時給自己發送)
                else if (mesType === 3) {
                    zxList.html("");
                    toList.html("<option value='ALL'>所有人</option>");
                    //
                    let userList = JSON.parse(content);
                    for (let i = 0; i < userList.length; i++) {
                        let userId = userList[i].userId;         // 用戶id
                        let username = userList[i].username;     // 用戶名
                        let createTime = userList[i].createTime; // 用戶登錄時間
                        // alert(userList[i].username)
                        if (userId !== from || userId !== formUserId) {
                            // 在線列表(id=用戶id,用於下線刪除)
                            zxList.html(zxList.html() + " <li id='" + userId + "' style='text-align: left'>---" + username + "&nbsp;&nbsp;&nbsp;&nbsp;" + createTime + "</li>");
                            // 在線人選擇框(optionId爲了下線通知移除) --》 不展示自己
                            toList.html(toList.html() + "<option id='option" + userId + "' value='" + userId + "'>" + username + "</option> ")
                        } else {
                            // 在線列表(id=用戶id,用於下線刪除)
                            zxList.html(zxList.html() + " <li id='" + userId + "' style='text-align: left'>---" + username + " (自己)&nbsp;&nbsp;&nbsp;&nbsp;" + createTime + "</li>");

                        }
                    }
                }

                // 信息接收通知
                else if (mesType === 4) {
                    if (to === "ALL") {
                        // 羣聊
                        // 判斷是否爲自己的消息,(自己 ==> 發送方=接收方 || 發送方是自己)
                        if (to === from || formUserId === from) {
                            //自己右邊展示
                            quLiao.html(quLiao.html() + " <li style='text-align: right;'>" + content + " <--" + username + " </li>");
                        } else {
                            //左邊展示
                            quLiao.html(quLiao.html() + " <li style='text-align: left;'>" + username + "--> " + content + " </li>");
                        }
                    } else {
                        // 私聊
                        // 判斷是否爲自己的消息,(自己 ==> 發送方=接收方 || 發送方是自己)
                        if (to === from || formUserId === from) {
                            //自己右邊展示
                            siLiao.html(siLiao.html() + " <li style='text-align: right;'>" + content + " <--" + username + " </li>");
                        } else {
                            //左邊展示
                            siLiao.html(siLiao.html() + " <li style='text-align: left;'>" + username + "--> " + content + " </li>");
                        }
                    }

                }
            };

            // 連接關閉的回調事件
            websocket.onclose = function () {
                console.log("連接已關閉...");
                document.getElementById('message').innerHTML += '連接已經關閉....' + '<br/>';
            };

        } else {
            // 瀏覽器不支持 WebSocket
            alert("您的瀏覽器不支持 WebSocket!");
        }


    /**
     * TODO 關閉websocket 連接 --> 關閉窗口也會自動斷開連接
     */
    function closeWebSocket() {
        //直接關閉websocket的連接
        websocket.close();
    }


    /**
     * TODO 按下Ctrl + 回車 發送消息
     */
    $(document).keyup(function (event) {
        //瀏覽器適應
        if (event.ctrlKey && event.which == 13 || event.which == 10) {
            send();
        } else if (event.shiftKey && event.which == 13 || event.which == 10) {
            send();
        }
    });


    /**
     * TODO 點擊發送按鈕發送消息
     */
    function send() {
        let to = $("#to").val();                  // 接收數據人id
        let content = $("#text").val();           // 發送的數據

        // 發送給指定人時,給自己也推送一個消息
        if (to !== "ALL") {
            to = to + "," + formUserId;
        }
        // 參數拼接
        let message = {
            "content": content,
            "to": to
        };
        //發送數據
        websocket.send(JSON.stringify(message));
        $("#text").val("");
    }
</script>
</html>


重點還是在與html 的js中獲取到參數如何處理參數,以及發送消息處理,到此可以先線上完成websocket 聊天功能了,
以及直接使用web-api 接口獲取到在線人數, 直接所有發送消息Api 接口向聊天室發送任意消息

本文到此結束,如果覺得有用,動動小手點贊或關注一下唄,將不定時持續更新更多的內容…,感謝大家的觀看!

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