Springboot的WebSocket示例

WebSocket

什么是WebSocket

             WebSocket为浏览器和服务端提供了双工异步通信的功能,即浏览器可以向服务器发送消息,服务器也可以向浏览器发送消息。WebScoket需浏览器的支持,如IE10+,Chrome13+,firefox6+,这对我们现在的浏览器来说都不是问题。

              WebSocket是通过一个socket来实现双工异步通信能力的。但是直接使用WebSocket(或者SockJS:WebSocket协议的模拟,增加了当浏览器不支持WebSocket的时候兼容支持)协议开发程序显得特别繁琐,我们会使用它的子协议STOMP,它是一个更高级别的协议,STOMP协议使用一个基于帧(frame)的格式来定义消息,与HTTP的request和response类似(具有类似于@RequestMapping和@MessageMapping),我们会在后面实战内容中观察STOMP的帧。

 Spring Boot提供的自动配置

                Spring Boot对内嵌的Tomcat7.8,jetty9和Undertow使用WebSocket提供了支持

准备,新建项目选择Thymeleaf和WebSocket依赖

广播式!!!!!!!!!!!!!!!!

广播式即服务端有消息时,会将消息发送给所有连接了当前endpoint的浏览器。

(1)配置WebSocket,需要在配置类上使用@EnableWebSocketMessageBroker开启WebSocket的支持,并通过继承

AbstractWebSocketMessageBrokerConfigurer类,重写其方法来配置WebSocket。

代码如下

package com.cn.sola.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Configuration
@EnableWebSocketMessageBroker //1
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {//2
		
		registry.addEndpoint("/endpointWisely").withSockJS();//3
	}
	
	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {//4
		// TODO Auto-generated method stub
		registry.enableSimpleBroker("/topic");//5
	}
}

(1)通过注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样。

(2)注册STOMP协议的节点(endpoint),并映射的指定的URL。

(3)注册一个STOMP的endpoint,并指定使用SockJS协议。

(4)配置消息代理(Message Broker)。

(5)广播式应配置一个/top消息代理。

浏览器向服务端发送消息用此类接收:

package com.cn.sola.bean;

public class WiselyMessage {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}

服务端向浏览器发送的此类的消息:

package com.cn.sola.bean;

public class WiselyResponse {
	
	private String responseMessage;
	
	public WiselyResponse(String responseMessage){
		
		this.responseMessage = responseMessage;
	}

	public String getResponseMessage() {
		return responseMessage;
	}

	public void setResponseMessage(String responseMessage) {
		this.responseMessage = responseMessage;
	}

}

演示控制器,代码如下

package com.cn.sola.controller;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

import com.cn.sola.bean.WiselyMessage;
import com.cn.sola.bean.WiselyResponse;

@Controller
public class WsController {

	@MessageMapping("/welcome") //1
	@SendTo("/topic/getResponse") //2
	public WiselyResponse say(WiselyMessage message) throws InterruptedException{
		
		Thread.sleep(3000);
		
		return new WiselyResponse("Welcome,"+message.getName()+"!");
		
	}
}

(1)当浏览器向服务端发送请求时,通过@MessageMapping映射/welcome这个地址类似于@RequestMapping。

(2)当服务端有消息时,会对订阅了@SendTo中的路径的浏览器发送消息。

---------------------------------------------------------------------------------------------------------------------

添加脚本。将stomp.min.js(STOMP协议的客户端脚本)、sockjs.min.js(SockJS的客户端脚本)以及JQuery放置在src/main/resources/static下。自行下载。

演示界面。在src/main/resources/template下建立ws.html代码如下

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Spring Boot+WebSocket广播式</title>
</head>
<body onload="disconnect()">
	<noscript>貌似你的浏览器不支持websocket</noscript>
	<div>
		<div>
			<button id="connect" onclick="connect();">连接</button>
			<button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
		</div>
		<div id="conversationDiv">
			<label>输入你的名字</label> <input type="text" id="name" />
			<button id="sendName" onclick="sendName();">发送</button>
			<p id="response"></p>
		</div>
	</div>
	<script th:src="@{sockjs.min.js}"></script>
	<script th:src="@{stomp.min.js}"></script>
	<script th:src="@{jquery-3.3.1.min.js}"></script>
	<script type="text/javascript">
		var stompClient = null;
		
		function setConnected(connected){
			document.getElementById('connect').disabled = connected;
			document.getElementById('disconnect').disabled = !connected;
			document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
		
			$('#response').html();
		}
		
		function connect(){
			
			var socket = new SockJS('/endpointWisely'); //1
			
			stompClient = Stomp.over(socket); //2
			
			stompClient.connect({},function(frame){ //3
			
			setConnected(true);
			
			console.log('Connected:' + frame);
			
			stompClient.subscribe('/topic/getResponse',function(respnose){ //4
				
				showResponse(JSON.parse(respnose.body).responseMessage);
			});
		});
		}
		
		function disconnect(){
			if(stompClient != null){
				
				stompClient.disconnect();
			}
			setConnected(false);
			console.log("Disconnected")
			
		}
		
		function sendName(){
			
			var name = $('#name').val();
			//5
			stompClient.send("/welcome",{},JSON.stringify({'name':name}));
			
		}
		
		function showResponse(message){
			
			var response = $("#response");
			
			response.html(message);
		}
	</script>
</body>
</html>

(1)连接SockJS的endpoint名成为“/endpointWisely”。

(2)使用STOMP子协议的WebSocket客户端。

(3)连接WebSocket服务端。

(4)通过stompClient.subscribe订阅/topic/getResponse目标(destination)发送的消息,这是在控制器的@SendTo定义的。

(5)通过stompClient.send向/welcome目标(destination)发送消息,这个是在控制器的@MessageMapping中定义的。

配置viewController,为ws.html提供便捷的路径映射:

package com.cn.sola.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class viewController extends WebMvcConfigurerAdapter{

	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		
		//这个就相当于映射一个地址
		registry.addViewController("/ws");
		//同上不加访问不到
		registry.addViewController("/ceshi");
	}
	
}

运行。我们预期的效果是:当一个浏览器发送一个小心到服务端时,其他的浏览器也能接收到从服务端发来的这个消息。

开启三个浏览器窗口,并访问localhost:8080/ws,分别连接服务器。然后在一个浏览器中发送一条消息,其它浏览器接收消息。

在浏览器F12可以看出连接服务端格式

猜你喜欢

转载自blog.csdn.net/jiulanhao/article/details/81126898