1. 程式人生 > >Spring4.0系列9-websocket簡單應用

Spring4.0系列9-websocket簡單應用

Spring 4.0的一個最大更新是增加了websocket的支援。websocket提供了一個在web應用中的高效、雙向的通訊,需要考慮到客戶端(瀏覽器)和伺服器之間的高頻和低延時訊息交換。一般的應用場景有:線上交易、遊戲、協作、資料視覺化等。

使用websocket需要考慮的瀏覽器的支援(IE<10不支援),目前主流的瀏覽器都能很好的支援websocket。

websocket協議中有一些子協議,可以從更高的層次實現程式設計模型,就像我們使用HTTP而不是TCP一樣。這些子協議有STOMP,WAMP等。

本教程只考慮websocket的簡單實用,包含Spring對JSR-356的支援及Spring WebSocket API。

1、Java API for WebSocket(JSR-356)

Java API for WebSocket已經是Java EE 7的一部分。它定義了兩類endpoit(都是EndPoint類的子類),使用註解標識@ClientEndpoint和@ServerEndpoint。

1.1 Servlet容器掃描初始化

通過Spring初始化一個endpoint,只需配置一個SpringConfigurator在類上的@ServerEndpoint註解上。

Java程式碼  收藏程式碼
  1. import javax.websocket.server.ServerEndpoint;  
  2. import
     org.springframework.web.socket.server.endpoint.SpringConfigurator;  
  3. @ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class);  
  4. publicclass EchoEndpoint {  
  5.   privatefinal EchoService echoService;  
  6.   @Autowired
  7.   public EchoEndpoint(EchoService echoService) {  
  8.     this.echoService = echoService;  
  9.   }  
  10.   @OnMessage
  11.   publicvoid handleMessage(Session session, String message) {  
  12.     // ...
  13.   }  
  14. }  

 上例假設SpringContextLoaderListener用來載入配置,這是個典型的web應用。Servlet容器將通過掃描@ServerEndpoint和SpringConfigurator初始化一個新的websocket會話。

 1.2 Spring 初始化

如果你想使用一個單獨的例項而不使用Servlet容器掃描,將EchoEndpoint類宣告稱一個bean,並增加一個ServerEndpointExporter的bean:

Java程式碼  收藏程式碼
  1. import org.springframework.web.socket.server.endpoint.ServerEndpointExporter;  
  2. @Configuration
  3. publicclass EndpointConfig {  
  4.   @Bean
  5.   public EchoEndpoint echoEndpoint() {  
  6.     returnnew EchoEndpoint(echoService());  
  7.   }  
  8.   @Bean
  9.   public EchoService echoService() {  
  10.     // ...
  11.   }  
  12.   @Bean
  13.   public ServerEndpointExporter endpointExporter() {  
  14.     returnnew ServerEndpointExporter();  
  15.   }  
  16. }  

 EchoEndpoint 可以通過EndPointRegistration釋出:

Java程式碼  收藏程式碼
  1. import org.springframework.web.socket.server.endpoint.ServerEndpointExporter;  
  2. import org.springframework.web.socket.server.endpoint.ServerEndpointRegistration;  
  3. @Configuration
  4. publicclass EndpointConfig {  
  5.   @Bean
  6.   public EndpointRegistration echoEndpoint() {  
  7.     returnnew EndpointRegistration("/echo", EchoEndpoint.class);  
  8.   }  
  9.   @Bean
  10.   public ServerEndpointExporter endpointExporter() {  
  11.     returnnew ServerEndpointExporter();  
  12.   }  
  13.   // ..
  14. }  

2、Spring WebSocket API

Spring WebSocket API提供了SockJS的支援,且有些容器如Jetty 9目前還沒有對JSR-356的支援,所以有Spring WebSocket API是必要的。

Spring WebSocket API的核心介面是WebSocketHandler。下面是一個處理文字訊息的handler的實現:

Java程式碼  收藏程式碼
  1. import org.springframework.web.socket.adapter.TextWebSocketHandlerAdapter;  
  2. publicclass EchoHandler extends TextWebSocketHandlerAdapter {  
  3.   @Override
  4.   publicvoid handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {  
  5.     session.sendMessage(message);  
  6.   }  
  7. }  

WebSocketHandler可以通過WebSocketHttpRequestHandler插入到Spring MVC裡:

Java程式碼  收藏程式碼
  1. import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;  
  2. @Configuration
  3. publicclass WebConfig {  
  4.   @Bean
  5.   public SimpleUrlHandlerMapping handlerMapping() {  
  6.     Map<String, Object> urlMap = new HashMap<String, Object>();  
  7.     urlMap.put("/echo"new WebSocketHttpRequestHandler(new EchoHandler()));  
  8.     SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();  
  9.     hm.setUrlMap(urlMap);  
  10.     return hm;  
  11.   }  
  12. }  

 SockJS伺服器端的支援

SockJs是一個指令碼框架,它提供類似於websocket的程式設計模式但是可以適應不同的瀏覽器(包括不支援websocket的瀏覽器)。

開啟SockJS的支援,宣告一個SockJsService,和一個url對映,然後提供一個WebSocketHandler來處理訊息。雖然我們是喲個SockJS我們開發的方式是一樣的,但是隨著瀏覽器的不同傳輸的協議可以是Http Streaming,long polling等。

Java程式碼  收藏程式碼
  1. import org.springframework.web.socket.sockjs.SockJsService;  
  2. // ...
  3. @Configuration
  4. publicclass WebConfig {  
  5.   @Bean
  6.   public SimpleUrlHandlerMapping handlerMapping() {  
  7.     SockJsService sockJsService = new DefaultSockJsService(taskScheduler());  
  8.     Map<String, Object> urlMap = new HashMap<String, Object>();  
  9.     urlMap.put("/echo/**"new SockJsHttpRequestHandler(sockJsService, new EchoHandler()));  
  10.     SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();  
  11.     hm.setUrlMap(urlMap);  
  12.     return hm;  
  13.   }  
  14.   @Bean
  15.   public ThreadPoolTaskScheduler taskScheduler() {  
  16.     ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();  
  17.     taskScheduler.setThreadNamePrefix("SockJS-");  
  18.     return taskScheduler;  
  19.   }  
  20. }  

在我們實際使用中我們會使用WebSocketConfigurer集中註冊WebSocket服務:

Java程式碼  收藏程式碼
  1. @Configuration
  2. @EnableWebMvc
  3. @EnableWebSocket//開啟websocket
  4. publicclass WebConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {  
  5.     @Override
  6.     publicvoid registerWebSocketHandlers(WebSocketHandlerRegistry registry) {  
  7.         registry.addHandler(echoWebSocketHandler(), "/echo"); //提供符合W3C標準的Websocket資料
  8.         registry.addHandler(snakeWebSocketHandler(), "/snake");  
  9.         registry.addHandler(echoWebSocketHandler(), "/sockjs/echo").withSockJS();//提供符合SockJS的資料
  10.         registry.addHandler(snakeWebSocketHandler(), "/sockjs/snake").withSockJS();  
  11.     }  
  12.     @Bean
  13.     public WebSocketHandler echoWebSocketHandler() {  
  14.         returnnew EchoWebSocketHandler(echoService());  
  15.     }  
  16.     @Bean
  17.     public WebSocketHandler snakeWebSocketHandler() {  
  18.         returnnew PerConnectionWebSocketHandler(SnakeWebSocketHandler.class);  
  19.     }  
  20.     @Bean
  21.     public DefaultEchoService echoService() {  
  22.         returnnew DefaultEchoService("Did you say \"%s\"?");  
  23.     }  
  24.     // Allow serving HTML files through the default Servlet
  25.     @Override
  26.     publicvoid configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {  
  27.         configurer.enable();  
  28.     }  
  29. }  

SockJS客戶端程式碼:

Java程式碼  收藏程式碼
  1. ws = new SockJS(url, undefined, {protocols_whitelist: transports}) ;   //初始化 websocket
  2. ws.onopen = function () {  
  3.                 setConnected(true);  
  4.                 log('Info: connection opened.');  
  5.             };  
  6. ws.onmessage = function (event) {  
  7.                 log('Received: ' + event.data); //處理服務端返回訊息
  8.             };  
  9. ws.onclose = function (event) {  
  10.                 setConnected(false);  
  11.                 log('Info: connection closed.');  
  12.                 log(event);  
  13.             };  
  14.  ws.send(message);//向服務端傳送訊息

 程式用maven打成war後用tomcat 8釋出檢視效果。

新書推薦《JavaEE開發的顛覆者: Spring Boot實戰》,涵蓋Spring 4.x、Spring MVC 4.x、Spring Boot企業開發實戰。

或自己在京東、淘寶、亞馬遜、噹噹、互動出版社搜尋自選。