标签搜索

目 录CONTENT

文章目录

SpringBoot之WebSocket学习

陈铭
2021-03-19 / 0 评论 / 0 点赞 / 139 阅读 / 999 字 / 正在检测是否收录...

引入依赖

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>

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

其中,spring-boot-starter-websocket就是实现websocket的关键依赖

配置

配置类

这里主要是注入一个ServerEndpointExporter对象,它主要用来管理ServerEndpoint,也就是进行websocket长连接的节点。当然,后续我们的节点都是设置在controller上。controller来接受请求,并且将请求绑定在一个长连接上。

@EnableWebSocket则是开启websocket服务,打开这个功能

@Configuration
@EnableWebSocket
public class WebSocketConfig {

	/**
	 * 注入ServerEndpointExporter;
	 * 该Bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
	 */
	@Bean
	public ServerEndpointExporter serverEndpointExporter() {
		return new ServerEndpointExporter();
	}

}

Controller

Controller(@ServerEndpoint)

Controller根据@ServerEndpoint也声明为了一个节点,里面有对应的方法注解,对应连接打开,收到消息等情况时应该执行的方法。并且前端要连接到这个controller应该用websocket协议(ws://xxxx)。

/**
 * 说明:
 * 1、@ServerEndpoint注解中指定WebSocket协议的地址;
 * 2、@OnOpen、@OnMessage、@OnClose、@OnError注解与WebSocket中监听事件对应
 * @author sec
 * @version 1.0
 * @date 2020/2/19 10:17 AM
 **/
@Slf4j
@RestController
@ServerEndpoint("/helper/{username}")
public class AssistantServerEndpoint {

	/**
	 * 连接建立时触发
	 */
	@OnOpen
	public void openSession(@PathParam("username") String username, Session session) {
		log.info("用户{}登录", username);
		String message = "欢迎用户[" + username + "] 已进入!";
		// 发送登录消息给其他人
		sendMessageAll(message);

		// 获取当前在线人数,发给自己
		String onlineInfo = WebSocketUtils.getOnlineInfo();
		WebSocketUtils.sendMessage(session, onlineInfo);

		// 添加自己到map中
		CLIENTS.put(username, session);
	}

	/**
	 * 客户端接收服务端数据时触发
	 */
	@OnMessage
	public void onMessage(@PathParam("username") String username, String message) {
		log.info("发送消息:{}", message);
		sendMessageAll("[" + username + "] : " + message);
	}

	/**
	 * 连接关闭时触发
	 */
	@OnClose
	public void onClose(@PathParam("username") String username, Session session) {
		//当前的Session移除
		CLIENTS.remove(username);
		// 离开消息通知所有人
		sendMessageAll("[" + username + "] 已离开!");
		try {
			session.close();
		} catch (IOException e) {
			log.error("onClose error", e);
		}
	}

	/**
	 * 通信发生错误时触发
	 */
	@OnError
	public void onError(Session session, Throwable throwable) {
		try {
			session.close();
		} catch (IOException e) {
			log.error("onError Exception", e);
		}
		log.info("Throwable msg " + throwable.getMessage());
	}

}

工具类WebSocketUtils

上述的controller发送信息主要用工具来实现,具体代码如下:

package com.secbro.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author sec
 * @version 1.0
 * @date 2020/2/26 9:10 AM
 **/
public final class WebSocketUtils {

	private static final Logger logger = LoggerFactory.getLogger(WebSocketUtils.class);

	/**
	 * 存储WebSocket session;<br/>
	 * 以用户的姓名为key,WebSocket为对象为value;
	 */
	public static final Map<String, Session> CLIENTS = new ConcurrentHashMap<>();

	/**
	 * 使用连接发送数据
	 * @param session 用户session
	 * @param message 发送内容
	 */
	public static void sendMessage(Session session, String message) {
		if (session == null) {
			return;
		}
		final RemoteEndpoint.Basic basic = session.getBasicRemote();
		if (basic == null) {
			return;
		}
		try {
			basic.sendText(message);
		} catch (IOException e) {
			logger.error("sendMessage IOException ", e);
		}
	}

	public static void sendMessageAll(String message) {
		CLIENTS.forEach((sessionId, session) -> sendMessage(session, message));
	}

	/**
	 * 获取所有在线用户
	 */
	public static String getOnlineInfo(){
		Set<String> userNames = CLIENTS.keySet();
		if(userNames.size() ==0){
			return "当前无人在线...";
		}
		return  CLIENTS.keySet().toString() + "在线";
	}

}

小结

小结

综上,为了实现SpringBoot的websocket功能,首先应该引入spring-boot-starter-websocket依赖;再配置好管理节点的对象ServerEndpointExporter;接着声明好节点ServerEndpoint,同时为了SpringBoot可以把接收到的请求分配给该节点,还要在这个节点上用上@Controller注解;最后在这个节点类上声明各种开启连接、收到消息的方法并注解。

但是,这种形式是可以实现简单的SpringBoot上的websocket功能,不过SpringBoot推荐的实现方式其实是基于STOMP协议的,大家有兴趣可以看看下一篇博客。

0

评论区