服务端和客户端四种事件
1、打开事件
此事件发生在端点上建立新连接时并且在任何其他时间发生之前。
方法级注解:@OnOpen
使用注解的的方法是没有任何返回值的公有方法,这些方法有一个可选的Session参数,一个可选的EndpointConfig参数,以及
任意数量的被@PathParam注解的String参数(这些参数的顺序是可以任意排列的)。
在案例中运用:
@OnOpen
public void whenOpening(Session session) {
this.session = session;
session.getUserProperties().put(START_TIME, System.currentTimeMillis());
this.sendMessage("3:Just opened");
}
2、消息事件
此事件接收WebSocket对话中另一端发送的消息。它发生在WebSocket端点接收了打开事件之后并且在接收关闭事件关闭连接之前的任意时刻。
方法级注解:@OnMessage
连接上的消息以3中基本形式抵达:文本消息、二进制消息、或pong消息。
方法可以有返回参数,当使用方法有返回参数时,WebSocket实现立即将返回值作为消息返回给刚刚在方法中处理的消息发送者。
在案例中运用
一、
//只接受文本消息,不处理其他格式消息
@OnMessage
public void whenGettingAMessage(String message) {
System.out.println("接收消息:"+message);
if (message.indexOf("xxx") != -1) {
throw new IllegalArgumentException("xxx not allowed !");
} else if (message.indexOf("close") != -1) {
try {
this.sendMessage("1:Server closing after " + this.getConnectionSeconds() + " s");
session.close();
} catch (IOException ioe) {
System.out.println("Error closing session " + ioe.getMessage());
}
return;
}
this.sendMessage("3:Just processed a message");
}
二、
//只接受二进制消息,不处理其他格式消息
@OnMessage
public void processBinary(byte[] messageDate,Session session) {
//代码逻辑
}
3、错误事件
此事件在WebSocket连接或者端点发生错误时产生。
方法级注解:@OnError
有三种基本类型的错误:
1、WebSocket实现产生的错误可能会发生。
2、错误可能发生在当WebSocket实现试图将入站消息解码成开发人员所要求的某个对象时。
3、最后由WebSocket端点的其他方法产生的运行错误。
在案例中运用
注意:第二种错误实际上调用的也是第一种注解方式
一、模拟异常错误
@OnError
public void whenSomethingGoesWrong(Throwable t) {
this.sendMessage("2:Error: " + t.getMessage());
}
二、模拟解析消息时自定义错误
4、关闭事件
此事件表示WebSocket端点的连接目前正在部分地关闭,它可以由参与连接的任意一个端点发出。
方法级注解:@OnClose
生命周期的最后一个事件
在案例中运用
一、模拟客户端关闭WebSocket
@OnClose
public void whenClosing() {
System.out.println("Goodbye !");
}
二、模拟客户端发送关闭请求,服务端关闭WebSocket
注意:其实方法二,最终调用过的也是方法一。所以当服务端或者客户端关闭WebSocket都是调用@OnClose方法。
案例运行:
1、开始界面
2、点击连接WebSocket端点(连接后可以进行操作)
3、发送消息(调用了@OnMessage 方法)
4、发送错误消息(会导致连接断开,先调用了@OncClose注解方法,判断消息不和规范抛出异常调用@OnError注解方法,之后调用@Onclose注解方法)
4、调用服务端关闭和调用客户端关闭操作(本质上调用的都是@Onclose注解方法)
实际上流程
服务端关闭:
1)先调用了@OnMessage注解方法,
2)判断入参为Close ,标识需要服务端关闭连接,服务端调用当前Session.Close()
3)然后调用@OnClose注解方法关闭WebSocket连接
客户端关闭
1)调用@OnClose注解方法关闭WebSocket连接
总结:
WebSocket声明周期
开始:通过@OnOpen开始
通讯:通过@OnMessage进行通讯
中断:@OnError 和 @OnClose 都会导致中断。
SpringBoot启动配置(配置完成直接运行此类就可以)
package Develop;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
/*
@SpringBootApplication
标注启动配置入口,可以发现通过一个main方法启动。
使用这个注解的类必须放置于最外层包中,因为默认扫描这个类以下的包。
否则需要自己配置@ComponentScan。
*/
public static void main(String[] arg){
SpringApplication.run(Application.class);
}
}
扫描服务端端点配置(如没有,则服务端端点无法实例化成功)
package Develop;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
服务端端点
package Develop.Lifecycle;
import org.springframework.stereotype.Component;
import java.io.IOException;
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;
@ServerEndpoint("/lights")
@Component
public class LifecycleEndpoint {
private static String START_TIME = "Start Time";
private Session session;
@OnOpen
public void whenOpening(Session session) {
this.session = session;
session.getUserProperties().put(START_TIME, System.currentTimeMillis());
this.sendMessage("3:Just opened");
}
@OnMessage
public void whenGettingAMessage(String message) {
System.out.println("接收消息:"+message);
if (message.indexOf("xxx") != -1) {
throw new IllegalArgumentException("xxx not allowed !");
} else if (message.indexOf("close") != -1) {
try {
this.sendMessage("1:Server closing after " + this.getConnectionSeconds() + " s");
session.close();
} catch (IOException ioe) {
System.out.println("Error closing session " + ioe.getMessage());
}
return;
}
this.sendMessage("3:Just processed a message");
}
@OnError
public void whenSomethingGoesWrong(Throwable t) {
this.sendMessage("2:Error: " + t.getMessage());
}
@OnClose
public void whenClosing() {
System.out.println("Goodbye !");
}
void sendMessage(String message) {
try {
session.getBasicRemote().sendText(message);
} catch (Throwable ioe) {
System.out.println("Error sending message " + ioe.getMessage());
}
}
int getConnectionSeconds() {
long millis = System.currentTimeMillis() -
((Long) this.session.getUserProperties().get(START_TIME));
return (int) millis / 1000;
}
}
客户端页面(可以自行更改服务端连接地址)
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Lifecycle</title>
</head>
<body>
<h1 style="text-align: center;">Lifecycle Lights</h1>
<table style="text-align: left; width: 50px; margin-left: auto;
margin-right: auto;" border="0" cellpadding="20" cellspacing="0">
<tbody>
<tr>
<td style=" text-align: center; vertical-align: top;">
<div style="text-align: center;">
<form action="">
<input value="Open Connection" type="button" id="ocID">
<input value="Send Message" type="button" id="svmID">
<input value="Send Bad Message" type="button" id="simID">
<input value="Server Close Connection" type="button" id="rccID">
<input value="Client Close Connection" type="button" id="rcID">
</form>
</div>
</td>
</tr>
<tr>
<td style=" text-align: center; vertical-align: top;">
<canvas id="myDrawing" width="200" height="210"></canvas>
<div id="traffic_light_display"></div>
</td>
</tr>
</tbody>
</table>
<div id="output"></div>
</body>
<script language="javascript" type="text/javascript">
var lifecycle_websocket;
function init() {
output = document.getElementById("output");
traffic_light_display = document.getElementById("traffic_light_display");
update_display("1", "No connection");
update_buttons();
}
function open_connection() {
lifecycle_websocket = new WebSocket("ws://localhost:8080/lights");
lifecycle_websocket.onmessage = function (evt) {
update_for_message(evt.data);
update_buttons();
};
lifecycle_websocket.onclose = function (evt) {
update_buttons();
};
}
function get_color(light_index, light_on_index) {
if (light_index == 1 && light_on_index == 1) {
return "red"
} else if (light_index == 2 && light_on_index == 2) {
return "yellow"
} else if (light_index == 3 && light_on_index == 3) {
return "green"
} else {
return "grey"
}
}
function get_light_index(message) {
return message.substring(0, 1)
}
function get_display_message(message) {
return message.substring(2, message.length)
}
function update_for_message(message) {
var display_message = get_display_message(message);
var light_index = get_light_index(message);
update_display(light_index, display_message);
}
function update_display(light_index, display_message) {
var old = traffic_light_display.firstChild;
var pre = document.createElement("pre");
pre.style.wordWrap = "break-word";
pre.innerHTML = "<b><font face='Arial'>"+display_message+"</font></b>";
if (traffic_light_display.firstChild != null) {
traffic_light_display.replaceChild(pre, traffic_light_display.firstChild);
} else {
traffic_light_display.appendChild(pre)
}
var context = document.getElementById('myDrawing').getContext('2d');
context.beginPath();
context.fillStyle = "black"
context.fillRect(65,0,70,210);
context.fill();
context.beginPath();
context.fillStyle = get_color(1, light_index); // grey
context.arc(100,35,25,0,(2*Math.PI), false)
context.fill();
context.beginPath();
context.fillStyle = get_color(2, light_index);
context.arc(100,105,25,0,(2*Math.PI), false)
context.fill();
context.beginPath();
context.fillStyle = get_color(3, light_index);
context.arc(100,175,25,0,(2*Math.PI), false)
context.fill();
}
function isOpen() {
return lifecycle_websocket != null && lifecycle_websocket.readyState == lifecycle_websocket.OPEN;
}
function update_buttons() {
ocID.disabled = isOpen();
simID.disabled = !isOpen();
svmID.disabled = !isOpen();
rccID.disabled = !isOpen();
rcID.disabled = !isOpen();
}
function send_valid_message() {
lifecycle_websocket.send("Hello")
}
function send_invalid_message() {
lifecycle_websocket.send("Helxxxlo")
}
function request_close_connection() {
lifecycle_websocket.send("close");
}
function close_connection() {
lifecycle_websocket.close();
update_display("1", "Client closed connection");
}
window.addEventListener("load", init, false);
</script>
</html>
maven依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<dependencies>
<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.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>8.0.53</version>
</dependency>
</dependencies>
代码结构
---------------------
作者:Mark_XC
来源:CSDN
原文:https://blog.csdn.net/Mark_Chao/article/details/82765818
版权声明:本文为博主原创文章,转载请附上博文链接!
|
|