SpringBoot使用WebSocket实现简易聊天室

直接上代码:

pom配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.3.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>websocket</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>websocket</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
WebSocketConfig.java
package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * Created by wdq on 2019/2/18.
 */
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}
WebSocketDemo.java
package com.example.demo;

import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import java.io.IOException;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

/**
 * Created by wdq on 2019/2/18.
 */
@ServerEndpoint("/ws/push/{userId}")
@Component
public class WebSocketDemo {

    // Hashtablex线程安全的map用来存储一登录用户信息,key为用户id。
    private static Hashtable<String, WebSocketDemo> userMap = new Hashtable<>();

    // 静态变量,用来记录当前在线连接数。
    private static int onlineCount = 0;

    // 与客户端的连接会话。
    private Session session;

    // 与客户端的连接的用户id。
    private String userId;

    //连接打开时执行
    @OnOpen
    public void onOpen(Session session,@PathParam("userId") String userId) throws IOException{
        System.out.println("新客户端接入,用户ID:" + userId);
        System.out.println("在线人数:" + WebSocketDemo.onlineCount);
        if(!StringUtils.isEmpty(userId)){
            //判断该用户是否已登录过
            if(!userMap.containsKey(userId)){
                this.userId = userId;
                this.session = session;
                userMap.put(userId,this); // 加入set中
                addOnlineCount(); // 在线数加1
            }
        }
        System.out.println("在线人数:" + WebSocketDemo.onlineCount);
    }

    //连接关闭调用的方法
    @OnClose
    public void onClose() {
        System.out.println("客户端关闭连接:"+this.userId);
        userMap.remove(this.userId); // 从map中删除
        subOnlineCount(); // 在线数减1
        System.out.println("在线人数:" + WebSocketDemo.onlineCount);
    }

    //收到客户端消息后调用的方法
    @OnMessage
    public void onMessage(String message, Session session) {
        if(!StringUtils.isEmpty(this.userId)){
            if(!"ping".equals(message)){//不是心跳检测
                //收到消息后可以去做一些具体的业务处理在推送,此处直接推送
                sendAll("【"+this.userId+"】"+message);
            }
        }else{
            System.out.println("当前客户未登陆:"+this.userId);
        }
        System.out.println("用户【"+this.userId+"】访问");
    }

    //发生错误时调用
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    public void sendMessage(String userId,String message){
        try {
            if(StringUtils.isEmpty(userId)){
                System.out.println("客户ID不能为空");
                return ;
            }
            for(Map.Entry<String, WebSocketDemo> entry : userMap.entrySet()){
                if(entry.getKey().equals(userId)){
                    entry.getValue().getSession().getBasicRemote().sendText(message);
                    System.out.println("推送给用户【"+entry.getKey()+"】消息成功,消息为:" + message);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendMessage(List<String> userIds,String message){
        try {
            if(userIds == null || userIds.size() == 0){
                System.out.println("客户ID不能为空");
                return ;
            }
            for(Map.Entry<String, WebSocketDemo> entry : userMap.entrySet()){
                if(userIds.contains(entry.getKey())){
                    entry.getValue().getSession().getBasicRemote().sendText(message);
                    System.out.println("推送给用户【"+entry.getKey()+"】消息成功,消息为:" + message);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendAll(String message){
        try {
            if(StringUtils.isEmpty(userId)){
                System.out.println("客户ID不能为空");
                return ;
            }
            for(Map.Entry<String, WebSocketDemo> entry : userMap.entrySet()){
                entry.getValue().getSession().getBasicRemote().sendText(message);
                System.out.println("推送给用户【"+entry.getKey()+"】消息成功,消息为:" + message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取连接人数
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    //连接人数加一
    public static synchronized void addOnlineCount() {
        onlineCount+=1;
    }
    //连接人数减一
    public static synchronized void subOnlineCount() {
        if(onlineCount > 0){
            onlineCount-=1;
        }
    }

    public Session getSession() {
        return session;
    }

}

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <title>保存更新</title>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>
    <style>
        input,textarea{
            box-sizing: border-box;
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
        }
    </style>
</head>
<body>
<input name="user" id="user" type="text" style="width: 100px"><button type="button" id="login">登录</button>
<form style="width: 300px;">
    <input name="tenantIds" placeholder="" style="width:100%;"  ><br>
    <button type="button" id="send" style="width:100%;" >提交</button><br>
    <div id="result" placeholder="结果提示" style="width:100%;height: 500px;border: gray solid 1px" ></div>
</form>
</body>
<script>
    var webSocket = null;
    $(document).ready(function () {
        //模拟不同用户,实际开发中从session或redis里取
        //判断当前浏览器是否支持WebSocket
        $("#login").click(function () {
            var user = $("#user").val();
            if("WebSocket" in window) {
                webSocket = new WebSocket("ws://localhost:8080/ws/push/" + user);
                displayMsg('用户【' + user + '】尝试连接')

                //连接发生错误的回调方法
                webSocket.onerror = function(){
                    displayMsg("服务器连接【异常】");
                };


                //连接成功建立的回调方法
                webSocket.onopen = function(event){
                    displayMsg('用户【'+user+'】服务器连接【成功】')
                    setInterval(function () {
                        webSocket.send("ping")
                    },10000)
                }


                //接收到消息的回调方法
                webSocket.onmessage = function(event){
                    displayMsg(event.data);
                }


                //连接关闭的回调方法
                webSocket.onclose = function(){
                    displayMsg("连接关闭");
                }


                //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
                window.onbeforeunload = function(){
                    websocket.close();
                }
            }else{
                displayMsg('当前浏览器可能不支持WebSocket')
            }
        })

        //关闭连接
        function closeWebSocket(){
            websocket.close();
        }

        $("#send").click(function () {
            var message = $("input[name=tenantIds]").val();
            if (message == "") {
                displayMsg("访问消息不能为空")
            } else {
                webSocket.send(message);
                displayMsg("已发送:" + message)
            }
        })

        //将消息显示在网页上
        function displayMsg(innerHTML){
            document.getElementById('result').innerHTML += innerHTML + '<br/>';
        }
    })
</script>
</html>

效果如下:

仅做笔记

发布了43 篇原创文章 · 获赞 126 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/W_DongQiang/article/details/87606741
今日推荐