未加星标

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

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二04 | 时间 2018 | 作者 红领巾 ] 0人收藏点击收藏
前言

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

关于WebSocket

WebSocket 是 HTML5 开始提供的一种在单个 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 表示连接状态,可以是以下值:
0 表示连接尚未建立。
1 表示连接已建立,可以进行通信。
2 表示连接正在进行关闭。
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));
}
} 注意点: @ServerEndpoint的value值填写时, 开头需要加上 / ,不然会提示路径无效。 需要加上类型 @Component 注解,使得能被扫描到。 这里的 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
发送消息

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

tags: WebSocket,session,message,gt,lt,userNick,String,Socket,连接,public,void,WebSocketUtil,websocket,注解,Session
分页:12
转载请注明
本文标题:SpringBoot | 第十九章:web 应用开发之 WebSocket
本站链接:https://www.codesec.net/view/597055.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(12)