Spring Boot整合WebSocket介绍 顶 原

WebSocket 简介

WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:

  • WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
  • WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。

整合示例

本示例为演示WebSocket的广播式模式,即服务端有消息时,会将消息发送给所有连接了当前endpoint的 Browser/Client Agent

 1. maven引入依赖包

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <boot.version>1.3.6.RELEASE</boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>${boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>${boot.version}</version>
        </dependency>
    </dependencies>

2. 编写WebSocket的配置类

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;

/**
 * @author ZhangPengFei
 * @Discription
 * @Data 2017-3-7
 * @Version 1.0.0
 */
@Configuration
//开启对WebSocket的支持
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{

	/**
	 * 注册一个STOMP协议的节点,并映射到指定的URL
	 * @param registry
	 */
	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		//注册一个STOMP的endpoint,并指定使用SockJS协议
		registry.addEndpoint("/endpointSocket").withSockJS();
	}

	/**
	 * 配置消息代理
	 * @param registry
	 */
	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {
		//配置一个广播式的消息代理
		registry.enableSimpleBroker("/topic");
	}
}

3. 浏览器向服务器端发送消息的实体封装类

/**
 * @author ZhangPengFei
 * @Discription
 * @Data 2017-3-7
 * @Version 1.0.0
 */
public class SocketMessage {
	private String message;

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
}

4. 服务器向浏览器响应数据的封装实体类

/**
 * @author ZhangPengFei
 * @Discription
 * @Data 2017-3-7
 * @Version 1.0.0
 */
public class SocketResponse {
	private String responseMessage;

	public SocketResponse(String responseMessage) {
		this.responseMessage = responseMessage;
	}

	public String getResponseMessage() {
		return responseMessage;
	}
}

5. 请求控制器

import com.os.china.entity.SocketMessage;
import com.os.china.entity.SocketResponse;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author ZhangPengFei
 * @Discription
 * @Data 2017-3-7
 * @Version 1.0.0
 */
@Controller
public class WebSocketController {

	private SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	//当浏览器向服务器端发送STOMP请求时,通过@MessageMapping注解来映射/getServerTime地址
	@MessageMapping(value = "/getServerTime")
	//当服务端有消息时,会对订阅了@SendTo中的路径的客户端发送消息
	@SendTo(value = "/topic/getResponse")
	public SocketResponse serverTime(SocketMessage message) throws InterruptedException {
		return new SocketResponse(message.getMessage() + sf.format(new Date()));
	}
}

6. 配置WebMvc视图映射

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

/**
 * @author ZhangPengFei
 * @Discription
 * @Data 2017-3-7
 * @Version 1.0.0
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
	/**
	 * MVC视图控制器配置
	 * @param registry
	 */
	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		//添加一个请求映射地址为/index,返回对应视图页面为webSocket
		registry.addViewController("/index").setViewName("/webSocket");
	}
}

7. 脚本添加,将 stomp.min.js(STOMP协议的客户端脚本),socketjs.min.js(SocketJS的客户端脚本)和 jQuery脚本放在src/main/resources/static下

注:STOMP协议的客户端连接详细介绍,请移步至我的另外一篇文章,WebSocket子协议STOMP详解 https://my.oschina.net/feinik/blog/853875

8. 在项目的src/main/resources/templates下新建webSocket.html页面

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>集成WebSocket示例</title>
</head>
<body>
<div>
    <button id="connect" onclick="connect();">连接</button>
    <button id="disconnect" onclick="disconnect();">断开连接</button>
    <button id="serverTimeId" onclick="getServerTime();">获取服务器端时间</button>
    <hr/>
    <span id="showServerTime"></span>
</div>
<script type="text/javascript" src="sockjs.min.js"></script>
<script type="text/javascript" src="stomp.min.js"></script>
<script type="text/javascript" src="jquery-3.1.1.min.js"></script>
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script type="text/javascript">
    var stompClient = null;
    $(function(){
        setConnect(false);
    });
    function setConnect(connected){
        $("#connect").attr({disabled:connected});
        $("#disconnect").attr({disabled:!connected});
    }
    function connect() {
        var socket = new SockJS('/endpointSocket');
        //创建STOMP客户端连接,目标地址为/endpointSocket的STOMP代理
        stompClient = Stomp.over(socket);
        //打印stomp输出信息
        stompClient.debug = function(str) {
            console.log(str + "\n");
        };
        //建立连接
        stompClient.connect({},function(frame) {
            setConnect(true);
            //连接成功后订阅/topic/getResponse目标发送的消息,该地址在Controller中用@SendTo指定
            stompClient.subscribe('/topic/getResponse', function(response) {
                showResponse(JSON.parse(response.body).responseMessage);
            });
        });
    }

    function disconnect() {
        if(stompClient != null) {
            stompClient.disconnect();
        }
        setConnect(false);
    }
    function getServerTime() {
        var message = "The server time is : ";
        //发送消息到服务端,/getServerTime地址是由Controller中的@MessageMapping指定
        stompClient.send("/getServerTime",{},JSON.stringify({'message':message}));
    }

    function showResponse(message){
        var response = $("#showServerTime");
        response.html(message);
    }

</script>
</body>
</html>

9. 编写SpringBoot的启动类

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

/**
 * @author ZhangPengFei
 * @Discription
 * @Data 2017-3-7
 * @Version 1.0.0
 */
@SpringBootApplication
public class ApplicationTest {

	public static void main(String[] args) {
		SpringApplication application = new SpringApplication(ApplicationTest.class);
		application.setBannerMode(Banner.Mode.OFF);
		application.run(args);
	}
}

10. 启动并测试,也可打开多个浏览器窗口连接到WebSocket服务端,在其中一个浏览器窗口中点击获取服务器时间,其他两个也将接收到消息

好了,整合到此完结,具体代码已上传至GitHub https://github.com/AIFEINIK/SpringBoot-Learn/tree/master/spring-boot-websocket

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章