Springboot + websocket

添加依赖:

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

进行设置:

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

/**
 * @author Fuyuanwu
 * @date 2019/11/7 16:24
 */
@Configuration
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    /**
     * 将"/hello"路径注册为STOMP端点,这个路径与发送和接收消息的目的路径有所不同,这是一个端点,客户端在订阅或发布消息到目的地址前,要连接该端点,
     * 即用户发送请求url="/applicationName/hello"与STOMP server进行连接。之后再转发到订阅url;
     * PS:端点的作用——客户端在订阅或发布消息到目的地址前,要连接该端点。
     *
     * @param stompEndpointRegistry
     */
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        // 在网页上可以通过"/applicationName/hello"来和服务器的WebSocket连接
        stompEndpointRegistry.addEndpoint("/hello").setAllowedOrigins("*").withSockJS();
    }

    /**
     * 配置了一个简单的消息代理,如果不重载,默认情况下回自动配置一个简单的内存消息代理,用来处理以"/topic"为前缀的消息。这里重载configureMessageBroker()方法,
     * 消息代理将会处理前缀为"/topic"和"/user"的消息。
     *
     * @param registry
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 服务端向客户端广播/发送消息时允许通过的代理。即,服务端想向客户端发送消息必须要要以 "/topic", "/user" 为前缀,否则消息就发不出去。
        registry.enableSimpleBroker("/topic", "/user");
        // 表示客户端向服务端 发送/订阅 消息的路径前缀。
        registry.setApplicationDestinationPrefixes("/web");
        // 服务端向单个客户端(点对点推送)时,服务器推送给客户端的路径前缀。
        registry.setUserDestinationPrefix("/user");
    }
}

编写用来测试的 controller :

import com.desuo.common.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SubscribeMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;

/**
 * @author Fuyuanwu
 * @date 2019/11/7 16:37
 */
@RestController
public class TestController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final SimpMessagingTemplate simpMessagingTemplate;

    public TestController(SimpMessagingTemplate simpMessagingTemplate) {
        this.simpMessagingTemplate = simpMessagingTemplate;
    }

    // 测试客户端主动发消息给服务端
    @MessageMapping("/message/test")
    public String receiveMessage(Principal principal, Book book) {
        logger.info("receive message principal name: {}", principal.getName());
        logger.info("这是客户端发过来的数据: {}", JsonUtil.writeValueAsString(book));
        // 测试:服务端主动发给客户端之广播消息。也可以用 @SendTo("/topic/message") 注解
        simpMessagingTemplate.convertAndSend("/topic/message", "这是一条服务端向你广播的消息");
        // 测试:服务端主动发给客户端之一对一消息。也可以用 @SendToUser("/topic/message/test") 注解
        simpMessagingTemplate.convertAndSendToUser(principal.getName(), "/topic/message/test", "这是一条服务端向你单独发送的消息");
        // 测试:向客户端的默认路径发送消息默认。默认路径的规则为 "/topic/" + @MessageMapping中的路径,所以这里的路径就是:/topic/message/test
        // 根据规则,客户端通过 subscribe 这个路径 /topic/message/test 可以收到return的消息
        return "这条是服务端接受到请求后,走默认路径给你返回的消息. receiveMessage";
    }

    // 测试客户端主动发订阅给服务端
    @SubscribeMapping("/subscribe/test")
    public String receiveSubscribe(Principal principal) {
        logger.info("receive subscriber principal name: {}", principal.getName());
        // 根据规则,客户端通过 subscribe 这个路径 /topic/subscribe/test 可以收到return的消息
        return "这条是服务端接受到请求后,走默认路径给你返回的消息. receiveSubscribe";
    }

    public static class Book {
        private String title;
        private String color;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getColor() {
            return color;
        }

        public void setColor(String color) {
            this.color = color;
        }
    }
}

前端向后端发送和接收消息:

let sock = new SockJS(this.serverUrls.material + '/hello')

let stompClient = this.stompClient = Stomp.over(sock)

stompClient.connect({}, function () {
    console.log('connected............')

    // 这个会接收到后台广播的消息
    stompClient.subscribe('/topic/message', function (message) {
      console.log('receive message form subscribe path: /topic/message', message)
    })
    // 这个会接收到后台点对点发送过来的消息
    stompClient.subscribe('/user/topic/message/test', function (message) {
      console.log('receive message form subscribe path: /user/topic/message/test', message)
    })
    // 这个是后台在接收到 前台通过 stompClient.send('/web/message/test'.....) 发出的消息后,后台延默认路径返回的消息。
    stompClient.subscribe('/topic/message/test', function (message) {
      console.log('receive message form subscribe path: /topic/message/test', message)
    })

    // 主动发送调阅消息给后台
    stompClient.subscribe('/web/subscribe/test', function (message) {
      console.log('receive message form subscribe path: /web/subscribe/test', message)
    })
    // 这个是后台在接收到 前台通过 stompClient.subscribe('/topic/subscribe'.....) 发出的订阅消息后,后台延默认路径返回的消息。
    stompClient.subscribe('/topic/subscribe', function (message) {
      console.log('receive message form subscribe path: /topic/subscribe', message)
    })


    // 主动发送消息给后台
    stompClient.send('/web/message/test', {}, JSON.stringify({title: 'Thinking in Java', color: 'yellow'}))
})

参考文档:

spring websocket:https://docs.spring.io/spring/docs/5.2.1.RELEASE/spring-framework-reference/web.html#websocket-stomp

stomp-js:https://stomp-js.github.io/api-docs/latest/classes/CompatClient.html

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