标签搜索

目 录CONTENT

文章目录

SpringBoot之STOMP协议

陈铭
2021-03-20 / 0 评论 / 0 点赞 / 317 阅读 / 1,041 字 / 正在检测是否收录...

引入依赖

pom依赖

和上一篇博客一样,spring-boot-starter-websocket才是关键的依赖,并且本篇博客主要讲的是STOMP协议的实现。

<dependencies>
    <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>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

配置

配置类

主要是注册STOMP节点,并配置订阅消息的路径前缀。

package com.secbro.config;

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

/**
 *
 * 注解@EnableWebSocketMessageBroker开启使用STOMP协议来传输基于代理的消息
 * @author sec
 * @version 1.0
 * @date 2020/2/26 9:06 AM
 **/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

	/**
	 * 注册STOMP协议的节点,并指定映射的URL
	 */
	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		// 注册STOMP协议节点
		registry.addEndpoint("/simple")
				// 解决跨域问题
				.setAllowedOrigins("*")
				// 指定端点使用SockJS协议
				.withSockJS();
	}

	/**
	 * 配置消息代理
	 */
	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {
		// 由于是实现推送功能,这里的消息代理是/topic
		// 启动简单Broker,消息的发送的地址符合配置的前缀来的消息才发送到这个broker
		registry.enableSimpleBroker("/topic");
	}

}


实体类

接受返回消息的实体类

@Data
public class RequestMessage {
	private String name;
}


@Data
public class ResponseMessage {
	private String message;
}

Controller和启动类

Controller

@MessageMapping("/hello"),前端发送消息的路径;而@SendTo("/topic/hello")是接收到消息后发送给订阅/topic/hello的用户。关于订阅的配置,上述配置类的registry.enableSimpleBroker("/topic")已经设置了订阅路径的前缀,没有这个订阅该路径不会被实现。

@Slf4j
@RestController
public class StompController {

	private static AtomicInteger index = new AtomicInteger();

	@Resource
	private SimpMessagingTemplate messagingTemplate;

	/**
	 * 注解@MessageMapping与@RequestMapping类似,定位请求地址;
	 * 注解@SendTo,指定当服务器有消息需要推送的时候,订阅了@SendTo中路径的客户端发送消息。
	 */
	@MessageMapping("/hello")
	@SendTo("/topic/hello")
	public ResponseMessage hello(RequestMessage message) {
		ResponseMessage resp = new ResponseMessage();
		String hello = "welcome," + message.getName() + " !";
		log.info("ResponseMessage:{}", hello);
		resp.setMessage(hello);
		return resp;
	}

	/**
	 * 定时推送消息,每隔两秒钟返回一次消息给订阅"/topic/callback"的客户端
	 */
	@Scheduled(fixedRate = 5000)
	public void callback() {
		// 发送消息
		messagingTemplate.convertAndSend("/topic/callback", "index: " + index.getAndIncrement());
	}
}

启动类

因为上述Controller开启了定时任务,所以启动类注解了@EnableScheduling

@EnableScheduling
@SpringBootApplication
public class SpringBootMainApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootMainApplication.class, args);
	}

}

JS代码

前端JS

stomp.js是为了支持STOMP协议;而sockjs.min.js是为了创建STOMP的对象,其中封装了websocket协议。

不像上一篇博客,new一个websocket对象(ws://xxx),new SockJS('http://localhost:8080/simple')才能正确连接上后端声明的STOMP节点,/simple已经在上述配置类声明了。之后就可以创建客户端对象(Stomp.over(socket)),根据该对象的订阅和发送方法,进行websocket长连接。


<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js"></script>
<script src="js/stomp.js"></script>
<script src="js/sockjs.min.js"></script>
<script type="text/javascript">

    $(document).ready(function () {
        var stompClient;
        var userName = $('#username').val();

        // WebSocket的连接地址
        var socket = new SockJS('http://localhost:8080/simple');
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {
            console.log('Connected:' + frame);

            // 客户端订阅消息的目的地址
            stompClient.subscribe('/topic/hello', function (response) {
                $('#content').append(JSON.parse(response.body).message + '\n');
            });

            // 客户端消息发送的目的地址,注册定时任务接收
            stompClient.subscribe('/topic/callback', function (response) {
                $('#content').append(response.body + '\n');
            });
        });

        // 客户端发送消息到服务器
        $('#toSend').click(function () {
            sendMsg();
        });

        $(document).keyup(function(event){
            // 回车键事件
            if(event.keyCode==13){
                sendMsg();
            }
        });

        function sendMsg(){
            stompClient.send("/hello", {}, JSON.stringify({'name': $('#message').val()}));
        }

        // 退出
        $('#user_exit').click(function () {
            if (stompClient != null) {
                stompClient.disconnect();
            }
            $('#content').append('[' + userName + '] 已离开!');
            console.log('Disconnected');
        });
    })
</script>

0

评论区