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