原 荐 SpringBoot | 第十九章:web应用开发之WebSocket

栏目: Html5 · 发布时间: 6年前

内容简介:在

前言

web开发 也讲解了三章了,这章节开始讲解关于与前端通信相关知识。实现一个在线聊天室类似的功能或者后端推送消息到前端,在没有 WebSocket 时,读大学那伙还有接触过 DWR(Direct Web Remoting) ,也使用过轮询的方式,当 Servlet3.0 出来后,也有使用其异步连接机制进行前后端通信的。今天我们就来说说 WebSocket 。它是 HTML5 开始提供的。

关于WebSocket

WebSocketHTML5 开始提供的一种在单个 TCP 连接上进行 全双工 通讯的协议。

WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

当获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

对于前端,创建一个 WebSocket 对象,如下:

var Socket = new WebSocket(url, [protocol] );

说明:第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。

WebSocker属性

以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 Socket 对象:

属性 描述
Socket.readyState 只读属性 readyState 表示连接状态,可以是以下值:<br>0 - 表示连接尚未建立。<br> 1 - 表示连接已建立,可以进行通信。<br>2 - 表示连接正在进行关闭。<br>3 - 表示连接已经关闭或者连接不能打开。
Socket.bufferedAmount 只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

WebSocket事件

以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 Socket 对象:

事件 事件处理程序 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发

WebSocket方法

以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 Socket 对象:

方法 描述
Socket.send() 使用连接发送数据
Socket.close() 关闭连接

WebSocket实践

前面介绍了在 浏览器端webSocket 的相关知识点,现在我们就来搭建一个后台对接应用,以实现一个简单的在线聊天室。

一点知识

后端关于 WebSocket 的实现是基于 JSR356 标准的。该标准的出现,统一了 WebSocket 的代码写法。只要支持web容器支持 JSR356 标准,那么实现方式是一致的。而目前实现方式有两种,一种是 注解 方式,另一种就是继承 继承javax.websocket.Endpoint 类了。

常用注解说明

  • @WebSocketEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端。注解的值将被用于监听用户连接的终端访问URL地址。

  • @onOpen 打开一个新连接,即有新连接时,会调用被此注解的方法。

  • @onClose 关闭连接时调用。

  • @onMessage 当服务器接收到客户端发送的消息时所调用的方法。

  • @PathParam 接收 uri 参数的,与@PathVariable功能差不多,可通过url获取对应值

搭建一个简易聊天室

0.加入 POM 依赖。

<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>

1.编写控制层,对应 WebSocket 的各事件。同时抽取了个公用类,进行通用方法调用。

WebSocketController.java

/**
 * websocket 简易聊天
 * @author oKong
 *
 */
//由于是websocket 所以原本是@RestController的http形式 
//直接替换成@ServerEndpoint即可,作用是一样的 就是指定一个地址
//表示定义一个websocket的Server端
@Component
@ServerEndpoint(value = "/my-chat/{usernick}")
@Slf4j
public class WebSocketController {
    
    /**
     * 连接事件 加入注解
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam(value = "usernick") String userNick,Session session) {
        String message = "有新游客[" + userNick + "]加入聊天室!";
        log.info(message);
        WebSocketUtil.addSession(userNick, session);    
        //此时可向所有的在线通知 某某某登录了聊天室            
        WebSocketUtil.sendMessageForAll(message);
    }
    
    @OnClose
    public void onClose(@PathParam(value = "usernick") String userNick,Session session) {
        String message = "游客[" + userNick + "]退出聊天室!";
        log.info(message);
        WebSocketUtil.remoteSession(userNick);    
        //此时可向所有的在线通知 某某某登录了聊天室            
        WebSocketUtil.sendMessageForAll(message);
    }
    
    @OnMessage
    public void OnMessage(@PathParam(value = "usernick") String userNick, String message) {
        //类似群发
        String info = "游客[" + userNick + "]:" + message;
        log.info(info);
        WebSocketUtil.sendMessageForAll(message);
    } 
    
    @OnError
    public void onError(Session session, Throwable throwable) {
        log.error("异常:", throwable);
        try {
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        throwable.printStackTrace();
    }

}

WebSocketUtil.java

public class WebSocketUtil {

    /**
     * 简单使用map进行存储在线的session
     * 
     */
    private static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();
    
    public static void addSession(String userNick,Session session) {
        //putIfAbsent 添加键—值对的时候,先判断该键值对是否已经存在
        //不存在:新增,并返回null
        //存在:不覆盖,直接返回已存在的值
//        ONLINE_SESSION.putIfAbsent(userNick, session);
        //简单示例 不考虑复杂情况。。怎么简单怎么来了。。
        ONLINE_SESSION.put(userNick, session);
    }
    
    public static void remoteSession(String userNick) {
        ONLINE_SESSION.remove(userNick);
    }
    
    /**
     * 向某个用户发送消息
     * @param session 某一用户的session对象
     * @param message
     */
    public static void sendMessage(Session session, String message) {
        if(session == null) {
            return;
        }
        // getAsyncRemote()和getBasicRemote()异步与同步
        Async async = session.getAsyncRemote();
        //发送消息
        async.sendText(message);
    }
    
    /**
     * 向所有在线人发送消息
     * @param message
     */
    public static void sendMessageForAll(String message) {
        //jdk8 新方法
        ONLINE_SESSION.forEach((sessionId, session) -> sendMessage(session, message));
    }
}

注意点:

  1. @ServerEndpoint的value值填写时, 开头需要加上 / ,不然会提示路径无效。
  2. 需要加上类型 @Component 注解,使得能被扫描到。
  3. 这里的 session 等,都在包** javax.websocket **包下的,注意区分。

2.编写主启动类,主要是加入注解 @EnableWebSocket 和申明一个 Websocket endpoint 类。

@SpringBootApplication
@EnableWebSocket
@Slf4j
public class Chapter19Application {

    public static void main(String[] args) {
        SpringApplication.run(Chapter19Application.class, args);
        log.info("Chapter19启动!");
    }
    
    /**
     * 会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     * 要注意,如果使用独立的servlet容器,
     * 而不是直接使用springboot的内置容器,
     * 就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

3.启动应用,利用在线的测试 工具 进行测试。这里直接使用了 http://coolaf.com/tool/chattest 进行测试。当然也可以自己写一个 html 了。

首先,输入我们的服务地址: ws://127.0.0.1:8080/my-chat/okong ,连接后就可以看见服务器返回的消息了。

原 荐 SpringBoot | 第十九章:web应用开发之WebSocket

我们再开一个标签页,然后继续以另一个身份进入:

原 荐 SpringBoot | 第十九章:web应用开发之WebSocket

这时,可以看见第一个页面开的,也收到消息了。现在我们发送一条消息:

原 荐 SpringBoot | 第十九章:web应用开发之WebSocket

然后,其中一个断开连接:

原 荐 SpringBoot | 第十九章:web应用开发之WebSocket

然后可以愉快聊天了,简单的一个聊天室就完成了。

参考资料

  1. https://docs.spring.io/spring/docs/4.3.18.RELEASE/spring-framework-reference/htmlsingle/#websocket
  2. https://docs.spring.io/spring-boot/docs/1.5.15.RELEASE/reference/htmlsingle/#boot-features-websockets
  3. http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html
  4. http://www.runoob.com/html/html5-websocket.html

总结

本章节主要是讲解了 WebSocket 的使用。因为有统一标准的存在,编写 webSocket 也是很简单的。对于如何一对一聊天,大家可以自行编写下,因为知道了对方名称,就能找出对方的 session 然后就能发送消息了。

最后

目前互联网上很多大佬都有 SpringBoot 系列教程,如有雷同,请多多包涵了。本文是作者在电脑前一字一句敲的,每一步都是自己实践的。若文中有所错误之处,还望提出,谢谢。

老生常谈

499452441
lqdevOps

原 荐 SpringBoot | 第十九章:web应用开发之WebSocket

个人博客: http://blog.lqdev.cn

完整示例: https://github.com/xie19900123/spring-boot-learning/tree/master/chapter-19

原文地址: http://blog.lqdev.cn/2018/08/14/springboot/chapter-nineteen/


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Numerical Methods and Methods of Approximation in Science and En

Numerical Methods and Methods of Approximation in Science and En

Karan Surana / CRC Press / 2018-10-31

ABOUT THIS BOOK Numerical Methods and Methods of Approximation in Science and Engineering prepares students and other readers for advanced studies involving applied numerical and computational anal......一起来看看 《Numerical Methods and Methods of Approximation in Science and En》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具