spring boot 2.x整合websocket——服务器端和客户端开发

一、前言

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

最近做的系统中,也涉及到websocket的使用,打算在这里记录一下相关知识,本篇博客主要包括:

  1. spring boot2.x整合websocket服务端;
  2. websocket客户端java代码版;
  3. websocket客户端HTML网页版。

二、服务端代码实现

  1. 创建一个spring boot工程,项目结构如下:

spring boot 2.x整合websocket——服务器端和客户端开发_第1张图片

  1. 导入相关maven依赖:
      <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>
  1. 自定义一个WebSocketServer服务类:
package com.learn.websocket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint("/websocketlearn/{id}") // websocket连接url
@Component
public class WebSocketServer {

    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    //存储当前server对象到map集合中
    private static final Map<String, WebSocketServer> clientMap = new ConcurrentHashMap<String, WebSocketServer>();
    // 当前会话
    private Session session;

    /**
     * websocket建立连接成功时调用
     *
     * @param id
     */
    @OnOpen
    public void onOpen(@PathParam("id") String id, Session session) {
        log.info("连接成功!");
        this.session = session;
        clientMap.put(id, this);
    }

    /**
     * 关闭连接时调用
     */
    @OnClose
    public void onClose(Session session) {
        log.info("关闭连接");
    }

    /**
     * 接收到客户端消息以后调用
     *
     * @param message
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("接收到消息:" + message);
    }

    /**
     * 发生异常时调用
     *
     * @param throwable
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        log.info("连接异常!" + throwable);
    }

    /**
     * 向指定id的客户端发送消息
     *
     * @param id
     * @param message
     */
    public void sendMessageToId(String id, String message) {
        WebSocketServer webSocketServer = clientMap.get(id);
        if (webSocketServer != null) {
            webSocketServer.session.getAsyncRemote().sendText(message);
        }
    }

    /**
     * 给所有用户进行推送信息
     *
     * @param message 推送的信息
     */
    public void sendMessageAll(String message) {
        for (WebSocketServer item : clientMap.values()) {
            item.session.getAsyncRemote().sendText(message);
        }
    }
}

  1. 增加websocket配置类WebSocketConfig:
@Configuration
public class WebSocketConfig {

    /**
     * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}
  1. 编写WebSocketController用于调用websocket服务端:
@RestController
@RequestMapping("/wsServer")
public class WebSocketController {
    
    @Autowired
    public WebSocketServer webSocketServer;

    /**
     * 给指定的用户推送信息
     *
     * @param id
     * @param message 
     */
    @GetMapping("/sendToClient")
    public void sendTo(String id, String message) {
        webSocketServer.sendMessageToId(id, message);
    }

    /**
     * 给所有用户推送信息
     *
     * @param msg 想要推送给用户的信息
     */
    @GetMapping("/sendAllClient")
    public void sendAll(String msg) {
        webSocketServer.sendMessageAll(msg);
    }

}

三、客户端代码实现(java代码版)

  1. 创建一个spring boot项目,项目结构如下:

spring boot 2.x整合websocket——服务器端和客户端开发_第2张图片

  1. 导入相关maven依赖:
        
            org.springframework.boot</groupId>
            spring-boot-starter-web</artifactId>
        </dependency>
        
            org.java-websocket</groupId>
            Java-WebSocket</artifactId>
            1.5.1</version>
        </dependency>
        
            org.springframework.boot</groupId>
            spring-boot-starter-test</artifactId>
            test</scope>
        </dependency>
  1. 修改当前客户端项目的端口,application.properties:
server.port=8081
  1. 编写websocket客户端,需要继承WebSocketClient,提供一个带参数的构造方法和实现其抽象方法:
package com.learn.websocket;


import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;

public class MyWebSocketClient extends WebSocketClient {

    private static final Logger log = LoggerFactory.getLogger(WebSocketClient.class);


    public MyWebSocketClient(URI serverUri) {
        super(serverUri);
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        log.info("连接成功!");
    }

    @Override
    public void onMessage(String s) {
        log.info("接收到服务端数据:" + s);
    }

    @Override
    public void onClose(int i, String s, boolean b) {
        log.info("关闭连接" + s);
    }

    @Override
    public void onError(Exception e) {
        log.info("发生异常" + e);
    }

}

  1. 创建websocket相关工具类:
public class WebSocketUtils {
    private static final Logger log = LoggerFactory.getLogger(WebSocketUtils.class);

    public static WebSocketClient webSocketClient(String id) {
        try {
            MyWebSocketClient webSocketClient = new MyWebSocketClient(new URI("ws://localhost:8080/websocketlearn/" + id));
            webSocketClient.connect();
            return webSocketClient;
        } catch (URISyntaxException e) {
            e.printStackTrace();
            log.error("创建websocket连接出现异常!", e);
        }
        return null;
    }
}
  1. 为了方便测试,编写一个WebSocketController调用websocket:
@RequestMapping("/wsclient")
@RestController
public class WebSocketController {

    private static final String CURRENT_ID = "1";

    WebSocketClient webSocketClient = WebSocketUtils.webSocketClient(CURRENT_ID);

    @RequestMapping("sendhllo")
    public void sendfirst(String message) {
        if(webSocketClient != null){
			webSocketClient.send("hello," + message + "!");
		}
    }

}

测试

  1. 分别启动服务端sp-websocket-server工程和客户端sp-websocket-client工程:

客户端启动时输出了日志:

在这里插入图片描述
表明,客户端与服务端连接成功。

  1. 访问:http://localhost:8081/wsclient/sendhllo?message=websocket服务器:

查看服务端控制台日志:

在这里插入图片描述
服务端成功接收到了信息。

  1. 访问:http://localhost:8080/wsServer/sendToClient?id=1&message=服务端已成功接收:
    查看客户端控制台日志:

在这里插入图片描述
已经实现了服务端和客户端正常通信。

四、客户端代码实现(HTML网页版)

编写websocket.html页面:


<html>
<head>
    <meta charset="UTF-8">
    <title>webSocketTesttitle>
head>

<body>
<input  id="id" type="text" />
<button onclick="oppen()">连接服务器button>
<hr>
<input  id="msg" type="text" />
<button onclick="sendMessage()">发送消息button>
<hr>
<button onclick="closeWebSocket()">关闭连接button>
<hr>
<div id="message">div>
body>

<script type="text/javascript">
    var websocket = null;

    //创建连接
    function oppen(){
        //判断当前浏览器是否支持WebSocket
        if('WebSocket' in window){
            var id = document.getElementById('id').value;
            if(id) {
                //连接WebSocket节点
                websockewt = new WebSocket("ws://localhost:8080/websocketlearn/" + id);
            }else {
                alert('请输入连接服务器的id')
            }
        }
        else{
            alert('Not support websocket')
        }

        //连接发生错误的回调方法
        websockewt.onerror = function(){
            setMessageInnerHTML("error");
        };

        //连接成功建立的回调方法
        websockewt.onopen = function(event){
            setMessageInnerHTML("open");
        }

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

        //连接关闭的回调方法
        websockewt.onclose = function(){
            setMessageInnerHTML("close");
        }
        //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
        window.onbeforeunload = function(){
            websockewt.close();
        }

        //将消息显示在网页上
        function setMessageInnerHTML(innerHTML){
            document.getElementById('message').innerHTML += innerHTML + '
'
; } } //关闭连接 function closeWebSocket(){ websockewt.close(); } //发送消息 function sendMessage(){ var message = document.getElementById('msg').value; websockewt.send(message); }
script> html>

测试

测试流程跟上面差不多,不做过多赘述,测试结果如下:

客户端:

spring boot 2.x整合websocket——服务器端和客户端开发_第3张图片
服务端:

访问链接:http://localhost:8080/wsServer/sendToClient?id=10&message=我很好啊,你呢。

在这里插入图片描述
可以看到,正常通信是没有问题的。

你可能感兴趣的:(java,web,springboot,websocket,spring,boot,websocket客户端,websocket服务端,java)