sockjs.js: 瀏覽器JavaScript庫,它提供了一個相似於網絡的對象。SockJS提供了一個連貫的、跨瀏覽器的Javascript API,它在瀏覽器和web服務器之間建立了一個低延遲、全雙工、跨域通訊通道。html
STOMP:簡單(流)文本定向消息協議,它提供了一個可互操做的鏈接格式,容許STOMP客戶端與任意STOMP消息代理(Broker)進行交互。有點像TCP和HTTP之間的關係,在websocket的通訊中,有了STOMP協議後,客戶端和服務端可以以更友好的方式進行交流。若是沒有提供第三方的STOMP代理,好比Rabbitmq等,那麼使用的就是spring容器本身提供的STOMP代理。web
可以使用sock.js創建websocket的客戶端鏈接。websocket可使用STOMP協議做爲傳輸的協議。spring
樣例代碼以下:json
@Configuration @EnableWebSocketMessageBroker //在 WebSocket 上啓用 STOMP public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { /** * 啓用了STOMP代理中繼功能:並將其目的地前綴設置爲 "/topic"; * spring就能知道 全部目的地前綴爲"/topic" 的消息都會發送到STOMP代理中; */ config.enableSimpleBroker("/topic", "/user"); /** * 設置了應用的前綴爲"app":全部目的地以"/app"打頭的消息(發送消息url not鏈接url) * 都會路由到帶有@MessageMapping註解的方法中,而不會發布到代理隊列或主題中; */ config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/webSocket").setAllowedOrigins("*").withSockJS(); } }
上面的配置中:跨域
stompClient.send("/app/webSocket/updateDevice", {}, JSON.stringify(req));
/app/websockt/send將由下面的代碼來進行處理:瀏覽器
@MessageMapping("/webSocket/send") public void updateDevice(SimpMessageHeaderAccessor headerAccessor, String requestContent) throws Exception { SubscriptionMsg msg = JSON.parseObject(requestContent, SubscriptionMsg.class); System.out.println(msg); }
STOMP消息代理的配置以下:服務器
config.enableSimpleBroker("/topic", "/user");
客戶端使用stompClient.subscribe("/topic/theme"),將經過STOMP訂閱在這個topic的主題.websocket
@Override public void configureMessageBroker(MessageBrokerRegistry registry) { // registry.setPathMatcher(new AntPathMatcher("."));//能夠已「.」來分割路徑,看看類級別的@messageMapping和方法級別的@messageMapping registry.enableSimpleBroker("/topic","/user"); registry.setUserDestinationPrefix("/user/"); registry.setApplicationDestinationPrefixes("/app");//走@messageMapping }
@RequestMapping("/app") @Controller public class WebSocketController { @Resource private SimpMessagingTemplate simpMessagingTemplate; @MessageMapping("/hello") // @SendTo("/topic/hello")//會把方法的返回值廣播到指定主題(「主題」這個詞並不合適) public void toTopic(SocketMessageVo msg , String name) { System.out.println(msg.getName()+","+msg.getMsg()); this.simpMessagingTemplate.convertAndSend("/topic/hello",msg.getName()+","+msg.getMsg()); // return "消息內容:"+ msg.getName()+"--"+msg.getMsg(); } @MessageMapping("/message") // @SendToUser("/message")//把返回值發到指定隊列(「隊列」實際不是隊列,而是跟上面「主題」相似的東西,只是spring在SendTo的基礎上加了用戶的內容而已) public void toUser(SocketMessageVo msg ) { System.out.println(msg.getName()+","+msg.getMsg()); this.simpMessagingTemplate.convertAndSendToUser("123","/message",msg.getName()+msg.getMsg()); } @RequestMapping("/sendMsg") public void sendMsg(HttpSession session){ System.out.println("測試發送消息:隨機消息" +session.getId()); this.simpMessagingTemplate.convertAndSendToUser("123","/message","後臺具體用戶消息"); } }
WebSocketConfig 中配置setApplicationDestinationPrefixes()的消息會被轉發到WebSocketController 中 @MessageMapping 相應方法進行處理。@SendTo("/topic/message") 會把方法的返回值序列化爲json串,而後發送到指定的主題,不用此註解,使用 simpMessagingTemplate.convertAndSend 效果相同;若爲 @SendToUser("/message") 則爲發送到指定的用戶隊列(實際隊列名字爲/user/用戶名/原隊列名),不用此註解,使用 simpMessagingTemplate.convertAndSendToUser() 效果相同;網絡
參考文檔:http://www.javashuo.com/article/p-fiuuyxpu-ed.htmlsession