SpringBoot 2.1.0 整合 Tomcat WebSocket 通信 - Go语言中文社区

SpringBoot 2.1.0 整合 Tomcat WebSocket 通信


目录

传统 Tomcat 开发 WebSocket 回顾

SpringBoot 整合 Tomcat  WebSocket

websocket 通信测试


传统 Tomcat 开发 WebSocket 回顾

1、WebSocket 的出现是基于 Web 应用的实时性需要而产生的,在淘宝、京东等网页客服、网页卖家聊天等需求上应用广泛。对于前端网页可以使用 H5 开发 WebSocket 客户端,也可以使用 SockJS 库开发 WebSocket 客户端。

2、对于Java 开发者而言,后台 WebSocket 服务端开发通常有以下常用的选择:

1、Tomcat7 以后开始支持 websocket 协议
2、Spring4 以后开始支持 WebSocket
3、Netty3 以后支持开发 WebSocket

3、Tomcat8 如下所示,自身已经支持 WebSocket 服务端开发,它的 lib 目录下有自己实现 WebSocket 协议的开发包,如果是传统的 Java Web 项目,则只需要将 tomcat-websocket.jar、websocket-api.jar 导入应用中即可进行代码开发。

4、Tomcat 自身也提供了 WebSocket 开发的示例,在 webapps/exampls下,一共提供了 4 个示例,可以启动 Tomcat 进行访问测试以及学习:

5、对于传统 Java Web 导包式应用开发,这里不再过多进行说明,它的基本流程是:

1)新建 Java Web 应用后,导入 Tomcat 服务器 lib 目录下的 websocket-api.jar 、tomcat-websocket.jar开发包,前者是浏览器 webSocket 规范的接口,后者是 Tomcat 对它的实现
2)创建后台 webSocket 服务端类,标识 @ServerEndpoint( javax.websocket.server.ServerEndpoint)注解,表示当前类是 webSocket 服务终端,同时在里面实现客户端连接建立、发送消息、接收消息等通信业务。
3)自己实现 javax.websocket.server.ServerApplicationConfig 接口,扫描整个应用所有的 @ServerEndpoint 服务终端

SpringBoot 整合 Tomcat  WebSocket

1、本文的重点是 SpringBoot 项目如何使用 Tomcat 的 webSocket 服务端开发。本文环境:springboot 2.1.0 ,使用内置的 Tomcat 服务器。

2、Spring boot 创建的 web 应用,web 启动模块已经依赖了 tomcat-websocket 模块,所以不需要再重复导入,  但是必须导入 Spring boot 的 websocket 启动模块 spring-boot-starter-websocket。

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

3、@ServerEndpoint 创建 websocket 服务终端

3.1、创建后台 webSocket 服务端类,标识 @ServerEndpoint( javax.websocket.server.ServerEndpoint)注解,表示当前类是 webSocket 服务终端,同时在里面实现客户端连接建立、发送消息、接收消息等通信业务。

3.2、这与传统导包式开发 Tomcat WebSocket 服务端是一样的,区别就是:传统方式 @ServerEndpoint 类上不需要加 @Component 交由 Spring 管理,而现在需要加上 @Component 将此组件交由 spring 管理。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/**
 * Created by Administrator on 2018/11/28 0028.
 * @ServerEndpoint :标识此类为 Tomcat 的 websocket 服务终端,/websocket/yy.action 是客户端连接请求的路径
 * @Component :将本类交由 spring IOC 容器管理
 */
@ServerEndpoint(value = "/websocket/yy.action")
@Component
public class ServerEnpoint {
    private static Logger logger = LoggerFactory.getLogger(ServerEnpoint.class);
    /**
     * 用 Set 来 存储 客户端 连接
     */
    private static Set<Session> sessionSet = new HashSet<>();
    /**
     * 连接成功后自动触发
     *
     * @param session
     */
    @OnOpen
    public void afterConnectionEstablished(Session session) {
        /**
         * session 表示一个连接会话,整个连接会话过程中它都是固定的,每个不同的连接 session 不同
         * String queryString = session.getQueryString();//获取请求地址中的查询字符串
         * Map<String, List<String>> parameterMap = session.getRequestParameterMap();//获取请求地址中参数
         * Map<String, String> stringMap = session.getPathParameters();
         * URI uri = session.getRequestURI();
         */
        sessionSet.add(session);
        logger.info("新客户端加入,session id=" + session.getId() + ",当前客户端格个数为:" + sessionSet.size());

        /**
         * session.getBasicRemote().sendText(textMessage);同步发送
         * session.getAsyncRemote().sendText(textMessage);异步发送
         */
        session.getAsyncRemote().sendText("我是服务器,你连接成功!");
    }
    /**
     * 连接断开后自动触发,连接断开后,应该清楚掉 session 集合中的值
     *
     * @param session
     */
    @OnClose
    public void afterConnectionClosed(Session session) {
        sessionSet.remove(session);
        logger.info("客户端断开,session id=" + session.getId() + ",当前客户端格个数为:" + sessionSet.size());
    }
    /**
     * 收到客户端消息后自动触发
     *
     * @param session
     * @param textMessage :客户端传来的文本消息
     */
    @OnMessage
    public void handleMessage(Session session, String textMessage) {
        try {
            logger.info("接收到客户端信息,session id=" + session.getId() + ":" + textMessage);
            /**
             * 原样回复文本消息
             * getBasicRemote:同步发送
             * session.getAsyncRemote().sendText(textMessage);异步发送
             * */
            session.getBasicRemote().sendText(textMessage);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 消息传输错误后
     *
     * @param session
     * @param throwable
     */
    @OnError
    public void handleTransportError(Session session, Throwable throwable) {
        System.out.println("shake client And server handleTransportError,session.getId()=" + session.getId() + " -- " + throwable.getMessage());
        logger.error("与客户端 session id=" + session.getId() + " 通信错误...");
    }
}

4、注入 ServerEndpointExporter

4.1、注入 org.springframework.web.socket.server.standard.ServerEndpointExporter,这个 bean 会自动注册使用了@ServerEndpoint 注解声明的 Websocket endpoint 。

4.2、如果使用独立的 servlet 容器,而不是使用 spring boot 的内置容器,就不要注入ServerEndpointExporter,因为它将由 Tomcat 容器自己提供和管理。

4.3、因为传统导包式 Tomcat websocket 开发时,是需要实现 javax.websocket.server.ServerApplicationConfig 接口的,然后由它去扫描整个应用中的 @ServerEndpoint,而现在这一步就由 springboot 的 ServerEndpointExporter 取代了。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
 * Created by Administrator on 2018/11/28 0028.
 */
@Configuration
public class WebSocketConfig {
    /**
     * 创建 ServerEndpointExporter 组件,交由 spring IOC 容器管理,
     * 它会自动扫描注册应用中所有的 @ServerEndpoint
     *
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

5、前端 H5 webSocket 客户端

5.1、为了方便,直接使用 H5 的 webSocket 方式,不清楚的可以参考《HTML5 WebSocket》,页面的 html 与 css 样式就不做提供了,直接提供客户端 webSocket 的 js 代码。

/**
 * web socket 绑定
 */
var ws = null;
function webSocketBind() {
    /**主流浏览器现在都支持 H5 d的 webSocket 通信,但建议还是要判断*/
    if ("WebSocket" in window) {
        /**创建 web socket 实例
         * 如果连接失败,浏览器控制台报错,连接失败
         * 前缀 ws:// 必须正确,yyServer 是应用名称,websocket/yy.action 是后台访问路径
         * 192.168.1.20:websocket 服务器地址
         * */
        ws = new WebSocket("ws://192.168.1.20/yyServer/websocket/yy.action");

        /**onopen:服务器连接成功后,自动触发*/
        ws.onopen = function () {
            /** Web Socket 已连接上,使用 send() 方法发送数据*/
                //ws.send("connect success...");
            console.log("服务器连接成功,并发送数据到后台...");
        };

        /**服务器发送数据后,自动触发此方法,客户端进行获取数据,使用 evt.data 获取数据*/
        ws.onmessage = function (evt) {
            var received_msg = evt.data;
            console.log("接收到服务器数据:" + received_msg);
            showClientMessage(received_msg);
        };

        /**客户端与服务器数据传输错误时触发*/
        ws.onerror = function (evt) {
            console.log("客户端 与 服务器 数据传输错误...");
        };

        /**web Socket 连接关闭时触发*/
        ws.onclose = function () {
            console.log("web scoket 连接关闭...");
        };
    } else {
        alert("您的浏览器不支持 WebSocket!");
    }
}

/**
 * 显示服务器发送的消息
 * @param message
 */
let showServerMessage = function (message) {
    if (message != undefined && message.trim() != "") {
        /**
         * 往服务器发送消息
         */
        ws.send(message.trim());
        /**
         * scrollHeight:div 区域内文档的高度,只能 DOM 操作,JQuery 没有提供相应的方法
         * @type {string}
         */
        let messageShow = "<div class='messageLine server'><div class='messageContent serverCon'>" + message + "</div><span>:我</span>";
        $(".centerTop").append(messageShow + "<br>");
        $(".messageArea").val("");

        let scrollHeight = $(".centerTop")[0].scrollHeight;
        $(".centerTop").scrollTop(scrollHeight - $(".centerTop").height());
    }
};

/**
 * 显示客户端的消息
 * @param message
 */
let showClientMessage = function (message) {
    if (message != undefined && message.trim() != "") {
        /**
         * scrollHeight:div 区域内文档的高度,只能 DOM 操作,JQuery 没有提供相应的方法
         * @type {string}
         */
        let messageShow = "<div class='messageLine client'><span>服务器:</span><div class='messageContent clientCon'>" + message + "</div>";
        $(".centerTop").append(messageShow + "<br>");
        $(".messageArea").val("");

        let scrollHeight = $(".centerTop")[0].scrollHeight;
        $(".centerTop").scrollTop(scrollHeight - $(".centerTop").height());
    }
};

$(function () {
    /**初始化后清空消息发送区域*/
    $(".messageArea").val("");

    /**
     * 为 消息 发送按钮绑定事件
     */
    $(".sendButton").click(function () {
        let message = $(".messageArea").val();
        showServerMessage(message);
    });

    /**
     * 绑定键盘敲击事件 —— 用于按 回车键 发送消息
     */
    $(window).keydown(function (event) {
        if (event.keyCode === 13) {
            let message = $(".messageArea").val();
            showServerMessage(message);
        }
    });
    /**
     * 绑定 webSocket,连接 服务器
     */
    webSocketBind();
});

websocket 通信测试

 

 

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/wangmx1993328/article/details/84582904
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-06-28 02:03:24
  • 阅读 ( 1295 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢