玩转 SpringBoot 2 之整合 WebSocket 篇

版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/ljk126wy/article/details/102589116

前言

本文主要介绍如何在SpringBoot 2 中使用 WebSocket 的快速搭建教程,阅读前需要你必须了解如何搭建 SpringBoot 项目。

在搭建前先来了解一下什么是 WebSocket,WebSocket 简单点说就是 HTML5 提供的基于 TCP 一种新的协议,它的作用就是:使浏览器和服务器只需要完成一次握手可以实现游览器和服务端的消息互相推送。具体详细描述可以查看 菜鸟教程相关介绍

闲话少说,接下来就直接开整 WebSocket 快速演示实战操作!

快速演示实战操作

第一步:需要引入WebSocket 的依赖,具体代码如下:

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

如果使用外置的 tomcat 需要引入 javaee-api 我们这里不引入是因为我们使用的是内置的tomcat,spring-boot 内置tomcat 包含拉 javaee-api 。

第二步:添加 WebSocket 配置类信息,也就是配置 WebSocket 服务端点。具体代码如下:

package cn.lijunkui.springbootlearn.socket.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
import javax.websocket.server.ServerEndpoint;
 
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

第三步: 开发创建连接、推送和处理消息的 Socket 处理类。

通过 @Controller + @ServerEndpoint("/访问地址名称") 注解 声明创建类为WebSocket 服务端点类。具体代码如下:

@Controller
@ServerEndpoint("/websocket")
public class Socket {
}

通过 CopyOnWriteArraySet 存放 WebSocket 连接 Session,并在声明 @OnOpen 的方法上获取并存放 Session。具体代码如下:

@Controller
@ServerEndpoint("/websocket")
public class Socket {
    /*websocket 客户端会话 通过Session 向客户端发送数据*/
    private Session session;
    /*线程安全set 存放每个客户端处理消息的对象*/
    private static CopyOnWriteArraySet<Socket> webSocketSet = new CopyOnWriteArraySet();
    /*websocket 连接建立成功后进行调用*/
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketSet.add(this);
        System.out.println("websocket 有新的链接"+webSocketSet.size());
    }
 }

定义监听客户端发送消息、Websocket 发生错误、WebSocket 连接关闭方法并通过 @OnMessage、@OnError,@OnClose进行声明。具体代码如下:

    /*WebSocket 连接关闭调用的方法*/
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
    }
    /*收到客户端消息后调用的方法*/
    @OnMessage
    public void onMessage(String message) throws IOException {
        for (Socket socket : webSocketSet) {
            socket.session.getBasicRemote().sendText("自己嘎给自己嘎发的消息:"+message);
        }
    }
    /* WebSocket 发生错误时进行调用*/
    @OnError
    public void onError(Session session,Throwable error){
        error.printStackTrace();
    }

通过 Session.getBasicRemote().sendText(String message) 想客户端推送消息。

    public void sendMessage(String message) throws IOException {
        for (Socket socket : webSocketSet) {
            socket.session.getBasicRemote().sendText(message);
        }
    }

详细代码如下:

package cn.lijunkui.socket;

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Controller;
@Controller
@ServerEndpoint("/websocket")
public class Socket {
	/*websocket 客户端会话 通过Session 向客户端发送数据*/
    private Session session;
    /*线程安全set 存放每个客户端处理消息的对象*/
    private static CopyOnWriteArraySet<Socket> webSocketSet = new CopyOnWriteArraySet();
    /*websocket 连接建立成功后进行调用*/
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketSet.add(this);
        System.out.println("websocket 有新的链接"+webSocketSet.size());
    }
    /*WebSocket 连接关闭调用的方法*/
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
    }
    /*收到客户端消息后调用的方法*/
    @OnMessage
    public void onMessage(String message) throws IOException {
        for (Socket socket : webSocketSet) {
            socket.session.getBasicRemote().sendText("自己嘎给自己嘎发的消息:"+message);
        }
    }
    /* WebSocket 发生错误时进行调用*/
    @OnError
    public void onError(Session session,Throwable error){
        error.printStackTrace();
    }
    public void sendMessage(String message) throws IOException {
        for (Socket socket : webSocketSet) {
            socket.session.getBasicRemote().sendText(message);
        }
    }
    public Session getSession() {
        return session;
    }
    public void setSession(Session session) {
        this.session = session;
    }
}

第四步:编写游览器向服务端推送消息页面 socket.html

通过 WebSocket(‘ws://WebScoket链接地址’) 对象建立和服务端的连接,并通过 WebSocket对象的 onopen、 onclose 、onmessage、onerror 来监听 WebSocket 连接成功、关闭、服务队推送消息、链接异常的信息。

通过 websocket.send(sendMessage) 方法向服务端推送消息。具体代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>socket demo</title>
</head>
<body>
    <h2>学说话的tom 猫</h2>
    <div><label>消息内容(服务端接受到消息并原样返回):</label><p id="serverMessage"></p></div>
    <div><label>我对自己说(游览器向服务端发送消息):</label><input id="sendMessage" type="text" />&nbsp;&nbsp;&nbsp;&nbsp;<button onclick="send()">发送</button></div>
 
<script type="text/javascript">
 
    var websocket = null;
    if('WebSocket' in window){
        websocket = new WebSocket('ws://localhost:8080/sbe/websocket');
    }else{
        alert("该游览器不知此WebSocket");
    }
    //websocket 链接成功后进行触发
    websocket.onopen = function (event){
        console.log("建立链接。。。。");
    }
    //websocket 链接关闭的进行触发
    websocket.onclose = function (event){
        console.log("关闭链接。。。。");
    }
    //接收到消息的进行触发
    websocket.onmessage = function(event){
        var serverMessage = document.getElementById("serverMessage");
        serverMessage.innerHTML= event.data;
        console.log("收到消息");
    }
 
    //连接发生错误的进行触发
    websocket.onerror = function(evt)
    {
        console.log("WebSocketError!");
    }
    //当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function (){
        websocket.close();
    }
    //关闭websocket连接
    function closeWebSocket(){
        websocket.close();
    }
    //发送消息
    function send(){
        var sendIput = document.getElementById("sendMessage");
        var sendMessage = sendIput.value;
        if(sendMessage.trim() == ""){
            alert("请输入发送消息!")
            return;
        }
        websocket.send(sendMessage);
    }
 
</script>
</body>
</html>

第五步:编写通过后台服务端发送消息到游览器的 Controller

package cn.lijunkui.springbootlearn.socket;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.io.IOException;
 
@RestController
@RequestMapping("socket")
public class SocketTestController {
    @Autowired
    private Socket socket;
    @GetMapping("/{message}")
    public void sendMessage(@PathVariable("message") String message) throws IOException {
        socket.sendMessage("这个是controller 发送的消息:"+message);
    }
}

第六步:编写通过后台发送消息到游览器的测试页面 controllerTest.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>直接向服务端发送消息</h2>
<input type="text" id="sendMessage"><button onclick="serverSendMsg()">发送</button>
</body>
<script language="JavaScript">
    function serverSendMsg(){
        var sendIput = document.getElementById("sendMessage");
        var sendMessage = sendIput.value;
        if(sendMessage.trim() == ""){
            alert("请输入发送消息!")
            return;
        }
        //创建异步对象
        var xhr = new XMLHttpRequest();
        //设置请求的类型及url
        xhr.open('get', 'http://localhost:8080/sbe/socket/'+sendMessage );
        //发送请求
        xhr.send();
        xhr.onreadystatechange = function () {
            // 这步为判断服务器是否正确响应
            if (xhr.readyState == 4 && xhr.status == 200) {
                console.log(xhr.responseText);
            }
        };
    }
</script>
</html>

测试

游览器向服务端发送消息测试:

打开游览器 访问socket.html 访问地址:http://localhost:8080/sbe/socket.html
在这里插入图片描述
直接向服务端发送消息测试

先访问socket.html 访问地址目的是先建立 WebSocket 的链接,然后访问直接向服务端发送消息测试页面,访问地址:http://localhost:8080/sbe/controllerTest.html
在这里插入图片描述
在这里插入图片描述

需要注意的是 必须访问 socket.html 建立连接后再访问 controllerTest.html 进行发送消息,否则会发送失败。

小结

SpringBoot 2 整合 WebSocket 主要分为三步:

  1. 引入websocket starter 依赖 。
  2. 添加 WebSocket 服务端点配置类信息以及 WebSocket 消息处理类(建立连接 接受和发送消息)。
  3. 在HTML页面通过 WebSocket 对象建立连接、接受和发送消息。

如果你还未曾使用过 WebSocket ,抓紧根据 快速演示实战操作 实操一下吧!

代码示例

我本地环境如下:

  • SpringBoot Version: 2.1.0.RELEASE
  • Apache Maven Version: 3.6.0
  • Java Version: 1.8.0_144
  • IDEA:Spring Tools Suite (STS)

整合过程如出现问题可以在我的GitHub 仓库 springbootexamples 中模块名为 spring-boot-2.x-websocket 项目中进行对比查看

GitHub:https://github.com/zhuoqianmingyue/springbootexamples

参考文献

猜你喜欢

转载自blog.csdn.net/ljk126wy/article/details/102589116
今日推荐