1. 程式人生 > 實用技巧 >springboot整合stomp實現 webScoket通訊

springboot整合stomp實現 webScoket通訊

1. 官網地址

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

2.入門示例

本示例在官網示例上稍加修改

2.1 依賴

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

2.2 新增websocket配置類

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;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic", "/queue");  // 相當於定義了兩個頻道
        config.setApplicationDestinationPrefixes("/app");  // 字首 , 與GreetingController類中@MessageMapping值一起使用("/app/hello")
        config.setUserDestinationPrefix("/queue");  // 表示其中queue這個頻道是用於   一對一發送資訊的. 預設是user
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/gs-guide-websocket")
                .setAllowedOrigins("*")
                .withSockJS();
    }

}

2.3 兩個普通的實體類, 訊息例項

public class Greeting {

  private String content;

  public Greeting() {
  }

  public Greeting(String content) {
    this.content = content;
  }

  public String getContent() {
    return content;
  }

}
public class HelloMessage {

  private String name;

  public HelloMessage() {
  }

  public HelloMessage(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

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

2.4 controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.HtmlUtils;

import javax.websocket.server.PathParam;
import java.security.Principal;
import java.time.LocalDateTime;

@RestController
public class GreetingController {

    @Autowired
    private SimpMessagingTemplate template;



    @GetMapping("/sendMsgToUser")
    public void sendMsgToUser() {
        HelloMessage message = new HelloMessage();
        message.setName("鄭欽鋒 to user," + LocalDateTime.now());
        // 一對一 [/queue/1/message]
        this.template.convertAndSendToUser("1", "/message", message);
    }

    /**
     * client可以直接將訊息傳送到指定的使用者
     * DestinationVariable註解與PathVariable功能差不多
     * <p>
     * 使用 @SendToUser註解將訊息傳送給指定的使用者還沒弄明白, 不然也可以使用註解來實現,省去template
     */
    @MessageMapping("/sendMsgToUser/{userId}")
    public void sendMsgToUser1(@DestinationVariable("userId") Long userId, HelloMessage message) {
        System.out.println(message.getName());
        System.out.println(userId);
        message.setName("one to one ," + LocalDateTime.now());
        this.template.convertAndSendToUser(String.valueOf(userId), "/message", message);
    }


    /**
     * 測試通過SimpMessagingTemplate傳送訊息到"/topic/greetings"頻道
     */
    @GetMapping("/sendMsg")
    public void sendMsg() {
        HelloMessage message = new HelloMessage();
        message.setName("鄭欽鋒," + LocalDateTime.now());
        // 將資訊傳送到"/topic/greetings"頻道,然後只要是訂閱了此頻道的client都能收到發信息
        this.template.convertAndSend("/topic/greetings", message);
    }



    /**
     * 客戶端可以通過@MessageMapping("/hello")[真實需要新增/app字首]這個地址將訊息傳送到 @SendTo("/topic/greetings")這個地址,
     * 然後訂閱了/topic/greetings這個地址的客戶端就可以收到訊息
     * <p>
     * ====================
     * 測試通過@SendTo註解傳送訊息到"/topic/greetings"
     */
    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public Greeting sendMsg1(HelloMessage message) throws Exception {
        Thread.sleep(1000); // simulated delay
        System.out.println(message.getName());
        return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
    }


}

2.5 客戶端實現

npm i stompjs -S
npm i sockjs-client -S
import SockJs from 'sockjs-client'
import Stomp from 'stompjs'
//測試websocket 通訊
connect() {
    // http://127.0.0.1:8989/api 是服務端根路徑 
    let socket = new SockJs('http://127.0.0.1:8989/api/gs-guide-websocket');
    let stompClient = Stomp.over(socket);
    stompClient.connect({}, function (frame) {
        console.log('連線服務端成功');
        console.log('Connected: ' + frame);

        // 接收訊息 (客戶端訂閱了"/topic/greetings/")
        // stompClient.subscribe('/topic/greetings/', function (greeting) {
        //     console.log(greeting);
        // });

        // 傳送訊息到/app/hello
        // stompClient.send('/app/hello', {}, JSON.stringify({name: '鄭欽鋒'}),)

        // stompClient.send('/app/sendMsgToUser/1', {}, JSON.stringify({name: '鄭欽鋒'}),)

        // 接收訊息 (一對一,感覺跟一對多一樣的)
        stompClient.subscribe('/queue/1/message', function (greeting) {
            console.log(greeting);
        });
    });

},

2.6 截圖