SpringBoot从入门到精通系列三:WebSocket


使用WebSocket能让客户端与服务端进行双向的实时通信。当客户端与服务端之间交互的内容较多或对实时性要求较高时,可使用WebSocket。

使用@ServerEndpoint开发WebSocket

Springboot的spring-boot-starter-websocket.jar为WebSocket提供了丰富的支持,使用这种方式来开发WebSocket服务器端程序非常简单,只要如下两步即可。

定义一个WebSocket处理类,该处理类有两种开发方式:

  • 直接使用JDK提供的WebSocket注解修饰处理方法,并使用@ServerEndpoint注解修饰该处理类即可。
  • 实现WebSocketHandler接口,并实现该接口中定义的各种处理方法。

采用第一种方式开发WebSocket处理类,这一步只需要在Spring容器中配置一个ServerEndpointExporter Bean即可。采用第二种方式开发WebSocket处理类,这一步就需要使用WebSocketConfigurer来配置WebSocket。

1.定义pom.xml

pom.xml
继承spring-boot-starter-parent,并添加spring-boot-starter-websocket.jar依赖

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<!-- 指定继承spring-boot-starter-parent POM文件 -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.2</version>
		<relativePath/>
	</parent>

	<groupId>org.crazyit</groupId>
	<artifactId>ServerEndpoint</artifactId>
	<version>1.0-SNAPSHOT</version>
	<name>ServerEndpoint</name>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>11</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<!-- 定义Spring Boot Maven插件,可用于运行Spring Boot应用 -->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

2.定义WebSocket处理类

接下来定义WebSocket处理类,并在该类中定义连接成功、收到消息、出现错误、连接关闭时的处理方法。

import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint("/websocket/{name}")
public class WebSocketEndpoint
{
	public static Map<Session, String> socketMap = new ConcurrentHashMap<>();
	// 连接建立成功触发的方法
	@OnOpen
	public void onOpen(@PathParam("name") String name, Session session)
	{
		socketMap.put(session, name);
	}
	// 连接关闭时触发的方法
	@OnClose
	public void onClose(Session session)
	{
		socketMap.remove(session);
	}
	// 收到客户端消息后触发的方法
	@OnMessage
	public void onMessage(String message, Session session)
	{
		System.out.printf("收到来自%s的消息:%s%n", session, message);
		try
		{
			var name = socketMap.get(session);
			for (var client: socketMap.keySet())	// ①
			{
				client.getBasicRemote().sendText(name + "说:" + message);
			}
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	// 发生错误时触发的方法
	@OnError
	public void onError(Session session, Throwable error)
	{
		System.out.println("发生错误");
		socketMap.remove(session);
	}
}
  • 该处理类定义了onOpen()、onClose()、onMessage()、onError()四个方法,并分别使用了@OnOpen、@OnClose、@OnMessage、@OnError注解修饰,表明这四个方法分别在建立连接、关闭连接、收到消息、遇到错误时被触发。
  • 使用这种方式开发WebSocket处理类更灵活,比如粗体字代码定义的onOpen()方法,该方法额外定义了一个用@PathParam修饰的形参,通过该形参即可获取路径参数。
  • 上面处理类使用Map保存WebSocketSession与客户端之间的对应关系,每当服务器接收到客户端发送过来的消息时,程序都会通过循环遍历Map中的每一个WebSocketSession,并逐一向它们发送接收到的消息,这样任意客户端发送消息都会被广播给所有客户端。

3.配置ServerEndpointExporter Bean

如下配置类

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();
	}
}
  • 上面配置类在Spring容器中配置了一个ServerEndpointExporter Bean,它专门负责读取Bean类上的@ServerEndpoint注解,并将该Bean导出为WebSocket Endpoint

3.使用JavaScript来开发WebSocket客户端

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title> 基于WebSocket的多人聊天 </title>
	<script type="text/javascript">
		// 定义Web Socket对象
		var webSocket = null;
		let sendMsg = function()
		{
			if (webSocket == null || webSocket.readyState != 1)
			{
				document.getElementById('show').innerHTML
					+= "还未连接服务器,请先连接WebSocket服务器<br>";
				return;
			}
			let inputElement = document.getElementById('msg');
			// 发送消息
			webSocket.send(inputElement.value);
			// 清空单行文本框
			inputElement.value = "";
		}
		let connect = function()
		{
			let name = document.getElementById('name').value.trim();
			if (name == null || name == "")
			{
				document.getElementById('show').innerHTML
					+= "用户名不能为空<br>";
				return;
			}
			if (webSocket && webSocket.readyState == 1)
			{
				webSocket.close();
			}
			webSocket = new WebSocket("ws://127.0.0.1:8080/websocket/" + name);
			webSocket.onopen = function()
			{
				document.getElementById('show').innerHTML
					+= "恭喜您,连接服务器成功!<br>";
				document.getElementById('name').value = "";
				// 为onmessage事件绑定监听器,接收消息
				webSocket.onmessage= function(event)
				{
					// 接收、并显示消息
					document.getElementById('show').innerHTML
						+= event.data + "<br>";
				}
			};
		}
	</script>
</head>
<body>
<input type="text" size="20" id="name" name="name"/>
<input type="button" value="连接" onclick="connect();"/>
<div style="width:600px;height:240px;
	overflow-y:auto;border:1px solid #333;" id="show"></div>
<input type="text" size="80" id="msg" name="msg"/>
<input type="button" value="发送" onclick="sendMsg();"/>
</body>
</html>

上面的JavaScript代码用到了HTML5的WebSocket规范,该页面代码需要支持HTML5规范的浏览器中运行。

4.主程序类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App
{
	public static void main(String[] args)
	{
		SpringApplication.run(App.class, args);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐骑行^_^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值