JS客户端调用WebSocket服务端,基于Springboot

目录

  • WebSocket服务端
    • 创建Springboot工程,引入WebSocket依赖
    • 配置WebSocketConfig
    • 配置WebSocketServer
  • JS客户端
    • 创建html页面
    • 编写JS客户端代码
  • 验证WebSocket通信

WebSocket服务端

简单说一下WebSocket,本身就是一种基于TCP的有状态的双向通信协议,可以实现即时通讯、消息推送等需要长连接的业务场景。

创建Springboot工程,引入WebSocket依赖

本示例引入的pom依赖如下:

<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.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

配置WebSocketConfig

代码如下

package com.websocket.config;

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

/**
 * WebSocket配置类
 * @author Neo
 */
@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter(){

        return new ServerEndpointExporter();

    }
}

配置WebSocketServer

代码如下

package com.websocket.server;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * WebSocket服务类
 * @author Neo
 */
@Slf4j
@ServerEndpoint(value = "/ws/server")
@Component
public class WebSocketServer {

    //存储每一个客户端会话信息的线程安全的集合
    private static final CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<>();
    //使用线程安全的计数器,记录在线数
    private static final AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 连接成功时调用的方法
     * @param session
     */
    @OnOpen
    public void onOpen(Session session) {
        //存储会话信息
        sessions.add(session);
        //计数+1
        int cnt = onlineCount.incrementAndGet();
        //打印日志
        log.info("有连接加入,当前连接数为:", cnt);
        //给客户端发消息
        this.sendMessage(session, "连接成功");
    }

    /**
     * 连接关闭时调用的方法
     * @param session
     */
    @OnClose
    public void onClose(Session session) {
        //删除会话信息
        sessions.remove(session);
        //计数-1
        int cnt = onlineCount.decrementAndGet();
        //打印日志
        log.info("有连接关闭,当前连接数为:", cnt);
    }

    /**
     * 收到客户端消息时调用的方法
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        //打印日志
        log.info("来自客户端的消息:",message);
        //给客户端发消息
        this.sendMessage(session, "收到消息,消息内容:"+message);
    }

    /**
     * 出现异常时调用的方法
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        //打印日志
        log.error("发生错误:Session ID:",error.getMessage(),session.getId());
    }

    /**
     * 发送消息
     * @param session
     * @param message
     */
    public void sendMessage(Session session, String message) {
        try {
            //发送消息
            session.getBasicRemote().sendText("SID:::" + session.getId() + ":::" + message);
        } catch (IOException e) {
            //打印日志
            log.error("发送消息出错:", e.getMessage());
        }
    }

    /**
     * 群发消息
     * 这个方法可以升级为消息推送的工具,给在线的客户端弹个广告啥的
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        for (Session session : sessions) {
            //判断连接是否开着
            if(session.isOpen()){
                //一个一个发
                sendMessage(session, message);
            }
        }
    }

    /**
     * 给指定的客户端发消息
     * 这个方法可以升级为即时通讯的工具,例如客户端A、客户端B、服务端WS
     * 首先,客户端要有身份id与WS的session进行绑定
     * 然后,A要给B发送消息,先获取B的身份id,然后将消息和B的身份id发给WS
     * WS收到A的消息后,拿着B的身份id去查询B与WS的会话信息,找到了,就把A的消息发送给B
     * @param sessionId
     * @param message
     * @throws IOException
     */
    public void sendMessage(String sessionId,String message) throws IOException {
        Session session = null;
        //遍历找会话信息
        for (Session s : sessions) {
            if(s.getId().equals(sessionId)){
                session = s;
                break;
            }
        }
        if(session!=null){
            //找到了,发消息
            this.sendMessage(session, message);
        } else{
            //打印日志
            log.warn("没有找到指定的会话:",sessionId);
        }
    }
}

到这里,WebSocket的服务端就配置完成了。

JS客户端

JS客户端其实就是一段运行在浏览器上的js代码,只要浏览器支持WebSocket协议,就可以与服务端进行通信

创建html页面

代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket</title>
</head>
<body>
JS客户端页面
</body>
</html>

编写JS客户端代码

直接在页面里编写就可以,代码如下

<script type="text/javascript">
    var socket;
    if (typeof (WebSocket) == "undefined") {
        console.log("很遗憾:您的浏览器不支持WebSocket");
    } else {
        console.log("恭喜您:您的浏览器支持WebSocket");

        //实现化WebSocket对象
        //指定要连接的服务器地址与端口建立连接
        socket = new WebSocket("ws://localhost:8080/ws/server");
        //连接打开事件
        socket.onopen = function() {
            console.log("Socket 已打开");
            socket.send("消息发送测试(From Client)");
        };
        //收到消息事件
        socket.onmessage = function(msg) {
            console.log(msg.data);
        };
        //连接关闭事件
        socket.onclose = function() {
            console.log("Socket已关闭");
        };
        //发生了错误事件
        socket.onerror = function() {
            alert("Socket发生了错误");
        }
        //窗口关闭时,关闭连接
        window.unload=function() {
            socket.close();
        };
    }
</script>

验证WebSocket通信

开启两个页面,打开控制台,看下效果,其它的验证就不介绍了,只要能连接上,啥都能解决!~
第一个页面:
JS客户端调用WebSocket服务端,基于Springboot_第1张图片
第二个页面:
JS客户端调用WebSocket服务端,基于Springboot_第2张图片

你可能感兴趣的:(SpringBoot)