SpringBoot 整合 websocket(一)

websocket

WebSocket是一种在单个TCP连接上进行全双工通信的协议。简单点说其实就是浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。例如现在很多网站的站内通信,点赞通知等及时通讯交互都可以用这个实现。具体的技术原理大家找度娘。

SpringBoot 整合websocket

引入jar包

SpringBoot 整合 websocket非常简单,只要引入websocket包即可

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

配置websocket

@Configuration
@ConditionalOnWebApplication
public class WebSocketConfig {

	/**
	 * ServerEndpointExporter 作用
	 *
	 * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
	 *
	 * @return
	 */
	@Bean
	public ServerEndpointExporter serverEndpointExporter() {
		return new ServerEndpointExporter();
	}
}

消息体定义

websocket的作用主要就是为了客户端和服务端通讯使用,既然是通讯,那么肯定有一些基本的参数,例如发送者、接收者,消息正文,消息发送时间等,这里可以定义一个消息体的对象。

public class WebSocketMsgVO implements Serializable {
	private static final long serialVersionUID = 6853050643035639834L;
	private String fromId;
	private String fromName;
	private String toId;
	private String toName;
	private String createDateTime;
	private String content;//消息正文
	private String sendMsgType;//发送消息的类型 :open/auto/dialog 
	private Map<String, Object> data = new HashMap<String, Object>();
}

前面6个字段看名字就知道什么意思了,就不多说了,主要是后面两个字段做个说明。
sendMsgType : 发送消息的类型,例如在浏览器连接上websocket时,服务器主动给浏览器推送“连接成功”提醒的消息(我这里定义成open),再例如会发送一些自动消息(auto),如果是2个客户之间正常的即时通话则定义为dialog。

data : 主要是为了扩展使用,例如不同的功能模块可以有一些特殊的信息,那么就放在这里。

websocket

@Component
@ServerEndpoint("/webSocket/{id}")
public class WebSocketServer {

	// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
	private static AtomicInteger onlineNum = new AtomicInteger();

	// concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
	private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();

	// 建立连接成功调用
	@OnOpen
	public void onOpen(final Session session, @PathParam(value = "id") final String id) {
		session.setMaxIdleTimeout(10 * 60 * 1000);
		try {
			synchronized (WebSocketServer.sessionPools) {
				if (WebSocketServer.sessionPools.containsKey(id)) {
					WebSocketServer.sessionPools.remove(id);
				} else {
					WebSocketServer.addOnlineCount();
				}
				WebSocketServer.sessionPools.put(id, session);
			}
			System.out.println(id + "加入webSocket!当前人数为" + WebSocketServer.onlineNum);
			final WebSocketMsgVO messageVO = new WebSocketMsgVO();
			messageVO.setToId(id);
			messageVO.setContent("欢迎" + id + "加入连接!");
			messageVO.setSendMsgType("open");
			sendMessage(session, HnJsonUtils.jsonToString(messageVO));
		} catch (final IOException e) {
			e.printStackTrace();
		}
	}

	// 关闭连接时调用
	@OnClose
	public void onClose(@PathParam(value = "id") final String id) {
		synchronized (WebSocketServer.sessionPools) {
			if (WebSocketServer.sessionPools.containsKey(id)) {
				WebSocketServer.sessionPools.remove(id);
				WebSocketServer.subOnlineCount();
			}
		}
		System.out.println(id + "断开webSocket连接!当前人数为" + WebSocketServer.onlineNum);
	}

	// 收到客户端信息
	@OnMessage
	public void onMessage(final String message) throws IOException {
		System.out.println("收到客户端消息:" + message);
		try {
			if (!WebSocketServer.sessionPools.isEmpty()) {
				final WebSocketMsgVO messageVO = HnJsonUtils.jsonToBean(message, WebSocketMsgVO.class);
				if (WebSocketServer.sessionPools.containsKey(messageVO.getToId())) {
					sendMessage(WebSocketServer.sessionPools.get(messageVO.getToId()), message);
				}
			}
		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	// 错误时调用
	@OnError
	public void onError(final Session session, final Throwable throwable) {
		System.out.println("发生错误");
		throwable.printStackTrace();
	}

	// 发送消息
	private void sendMessage(final Session session, final String message) throws IOException {
		if (session != null) {
			synchronized (session) {
				System.out.println("发送数据:" + message);
				session.getBasicRemote().sendText(message);
			}
		}
	}

	public static void addOnlineCount() {
		WebSocketServer.onlineNum.incrementAndGet();
	}

	public static void subOnlineCount() {
		WebSocketServer.onlineNum.decrementAndGet();
	}
}

从代码中的各个方法名称基本就能看出来websocket的工作原理和流程。
1.客户端连接服务器端,触发onOpen()
2.当客户端发送消息,服务器端通过onMessage()接收,并通过sendMessage()推送到相应的接收者浏览器,然后由前端的websocket来接收处理消息。

application.yml

server:
  port: 9990
  servlet:
    context-path: /socketweb

前端socket.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket</title>
    
</head>
<body>
<h3>hello socket</h3>
<p>【fromId】:<div><input id="fromId" name="fromId" type="text" value="google"></div>
<p>【toId】:<div><input id="toId" name="toId" type="text" value="firefox"></div>
<p>【内容】:<div><input id="content" name="content" type="text" value="hello firefox, 这是个测试的websocket"></div>
<p>【操作】:<input type="button" onclick="openSocket()" value="开启socket" />
<p>【操作】:<input type="button" onclick="sendMessage()"value="发送消息" />
<ul id="cont"></ul>
</body>
<script type="text/javascript">
    

    var socket;
    function openSocket() {
        if(typeof(WebSocket) == "undefined") {
            console.log("您的浏览器不支持WebSocket");
        }else{
            console.log("您的浏览器支持WebSocket");
            //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
            var fromId = document.getElementById('fromId').value;
            var socketUrl="ws://127.0.0.1:9990/socketweb/webSocket/"+fromId;
            console.log(socketUrl);
            if(socket!=null){
                socket.close();
                socket=null;
            }
            socket = new WebSocket(socketUrl);
            //打开事件
            socket.onopen = function() {
                console.log("websocket已打开");
                //socket.send("这是来自客户端的消息" + location.href + new Date());
            };
            //获得消息事件
            socket.onmessage = function(msg) {
                var serverMsg = "收到服务端信息:" + msg.data;
                console.log(serverMsg);
                var message=JSON.parse(msg.data);
               var node=document.createElement("LI");
		 var textnode=document.createTextNode(message.content);
		 node.appendChild(textnode);
               document.getElementById("cont").appendChild(node);
            };
            //关闭事件
            socket.onclose = function() {
                console.log("websocket已关闭");
            };
            //发生了错误事件
            socket.onerror = function() {
                console.log("websocket发生了错误");
            }
        }
    }
    function sendMessage() {
        if(typeof(WebSocket) == "undefined") {
            console.log("您的浏览器不支持WebSocket");
        }else {
            // console.log("您的浏览器支持WebSocket");
            var fromId = document.getElementById('fromId').value;
            var toId = document.getElementById('toId').value;
            var content = document.getElementById('content').value;
            var jsonMsg={fromId:fromId,toId:toId,content:content,sendMsgType:"dialog"};
            console.log(jsonMsg);
            socket.send(JSON.stringify(jsonMsg));
        }
    }

    </script>
</html>

效果

在这里插入图片描述

思考

以上就是最简单的实现websocket即时通讯的方法,但这里只是实现了单个通道下即时通讯的功能,在正式的项目中可能还是有问题的,例如正式环境下是有多个服务器做负载均衡的,这个时候就会导致不同的客户端在与服务器握手时会连接道不同的服务器上,这样也就导致发送到服务器上的消息在推送时找不到对应的客户端,那么就需要换另外的做法了。这块下次有时间在写了 。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现Spring Boot整合WebSocket,你需要进行以下步骤: 1. 首先,在pom.xml文件中添加WebSocket的相关依赖。可以使用以下两个依赖之一: - 从中提到的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` - 从中提到的依赖: ```xml <!--webSocket--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建WebSocket配置类,这个类负责配置WebSocket的相关信息。你可以按照以下方式创建一个配置类[3]: ```java package com.loit.park.common.websocket; 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(); } } ``` 3. 至此,你已经完成了WebSocket整合配置。现在,你可以在你的应用中创建WebSocket的控制器并定义你的WebSocket端点。你可以根据你的需求来实现WebSocket端点的业务逻辑。 这就是Spring Boot整合WebSocket的基本步骤。通过这种方式,你可以在Spring Boot应用中轻松地使用WebSocket进行实时通信。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [springboot整合websocket](https://blog.csdn.net/weixin_45390688/article/details/120448778)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [springboot整合websocket(详解、教程、代码)](https://blog.csdn.net/hjq_ku/article/details/127503180)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值