1. 程式人生 > >spring websocket + stomp 實現廣播通訊和一對一通訊

spring websocket + stomp 實現廣播通訊和一對一通訊

spring對於基於stomp協議的websocket通訊,其官網上面有一個guide,但是根據guide你只能寫出來廣播方式的通訊,不能實現一對一的通訊,這篇文章在這裡把廣播和一對一一起整理一下給大家。

服務端:

一,依賴,spring-websocket和spring-messaging,這裡給出maven方式:

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>${spring-core.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
            <version>${spring-core.version}</version>
        </dependency>

二,服務端程式碼:

服務端的初始化,只需要兩個類:WebsocketConfig和WebSocketController

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
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

	@Override
	public void configureMessageBroker(MessageBrokerRegistry config) {
		config.enableSimpleBroker("/topic","/user");
		config.setApplicationDestinationPrefixes("/app");
        config.setUserDestinationPrefix("/user/");
	}

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/webServer").withSockJS();
	}

}

這個類表示啟用websocket訊息處理,以及收發訊息的域

config.enableSimpleBroker("/topic","/user");這句表示在topic和user這兩個域上可以向客戶端發訊息;config.setUserDestinationPrefix("/user/");這句表示給指定使用者傳送(一對一)的主題字首是“/user/”;  config.setApplicationDestinationPrefixes("/app"); 這句表示客戶端向服務端傳送時的主題上面需要加"/app"作為字首;registry.addEndpoint("/webServer").withSockJS();這個和客戶端建立連線時的url有關,後面在客戶端的程式碼中可以看到。


下面是一個spring風格的controller,用於接收客戶端的訊息及響應客戶端:

import org.springframework.beans.factory.annotation.Autowired;
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;

@Controller
public class WebSocketController {

    public SimpMessagingTemplate template;

    @Autowired
    public WebSocketController(SimpMessagingTemplate template) {
        this.template = template;
    }

    @MessageMapping("/hello")
    @SendTo("/topic/hello")
    public Greeting greeting(Greeting message) throws Exception {
        return message;
    }

    @MessageMapping("/message")
    @SendToUser("/message")
    public UserMessage userMessage(UserMessage userMessage) throws Exception {
        return userMessage;
    }

}
這個類裡面織入SimpMessagingTemplate物件,後面動態傳送訊息時,需要用到這個物件。

第一個方法,表示服務端可以接收客戶端通過主題“/app/hello”傳送過來的訊息,客戶端需要在主題"/topic/hello"上監聽並接收服務端發回的訊息

第二個方法道理相同,只是注意這裡用的是@SendToUser,這就是傳送給單一客戶端的標誌。本例中,客戶端接收一對一訊息的主題應該是“/user/” + 使用者Id + “/message” ,這裡的使用者id可以是一個普通的字串,只要每個使用者端都使用自己的id並且服務端知道每個使用者的id就行。

這裡的Greeting和UserMessage是一個普通的實現了序列化的java bean

就這樣,那麼,在程式中的其他地方要動態傳送訊息,就是下面這兩句程式碼:

webSocketController.template.convertAndSend("/topic/hello",greeting) //廣播
webSocketController.template.convertAndSendToUser(userId, "/message",userMessage) //一對一發送,傳送特定的客戶端

客戶端:

js客戶端需要匯入兩個js元件:sockjs-0.3.4.js,stomp.js

var url = 'http://localhost:8080/appRoot/webServer'
var socket = new SockJS(url, undefined, {protocols_whitelist: ['websocket']});
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
	stompClient.subscribe('/topic/hello', function(message){
		var json = JSON.parse(message.body);
	});

	 stompClient.subscribe('/user/' + userId + '/message', function(message){
		 var messageEntity = JSON.parse(message.body);
	});
});

第一個subscribe,是接收廣播訊息,第二個是接收一對一訊息,其主題是'/user/' + userId+ '/message' , 不同客戶端具有不同的userId

看到這裡,你會發現,這裡所謂的一對一,只是業務層面的一對一,也就是,需要不同客戶端具有不同的userId才能實現,如果兩個客戶端使用相同的userid, 那麼服務端給這個userId傳送訊息時,這兩個客戶端都會收到。要真正實現websocket技術層面的一對一發送,那就要使用websocket的session了。關於session方式,我這裡上傳一個demo,有興趣可以下載:http://download.csdn.net/detail/valenon/8725195