Spring4.0 + websocket simple application

One of the biggest updates in Spring 4.0 is the addition of websocket support. Websockets provide an efficient, two-way communication in web applications, taking into account the high-frequency and low-latency message exchange between the client (browser) and the server. General application scenarios include: online transactions, games, collaboration, data visualization, etc.

 

Browser support needs to be considered when using websocket (IE<10 does not support it). Currently, mainstream browsers can support websocket very well.

There are some sub-protocols in the websocket protocol, which can realize the programming model from a higher level, just like we use HTTP instead of TCP. These sub-protocols include STOMP, WAMP, etc.

This tutorial only considers the simplicity and practicality of websocket, including Spring's support for JSR-356 and Spring WebSocket API.

1、Java API for WebSocket(JSR-356)

The Java API for WebSocket is already part of Java EE 7. It defines two types of endpoints (both subclasses of the EndPoint class), using annotations to identify @ClientEndpoint and @ServerEndpoint.

 

1.1 Servlet container scan initialization

To initialize an endpoint through Spring, just configure a SpringConfigurator on the @ServerEndpoint annotation on the class.

    import javax.websocket.server.ServerEndpoint;  
    import org.springframework.web.socket.server.endpoint.SpringConfigurator;  
      
      
    @ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class);  
    public class EchoEndpoint {  
      
      private final EchoService echoService;  
      
      @Autowired  
      public EchoEndpoint(EchoService echoService) {  
        this.echoService = echoService;  
      }  
      
      @OnMessage  
      public void handleMessage(Session session, String message) {  
        // ...  
      }  
      
    }  

The above example assumes that SpringContextLoaderListener is used to load configuration, which is a typical web application. The Servlet container will initialize a new websocket session by scanning @ServerEndpoint and SpringConfigurator.

 1.2 Spring initialization

If you want to use a single instance without Servlet container scanning, declare the EchoEndpoint class as a bean and add a ServerEndpointExporter bean:

    import org.springframework.web.socket.server.endpoint.ServerEndpointExporter;  
      
      
    @Configuration  
    public class EndpointConfig {  
      
      @Bean  
      public EchoEndpoint echoEndpoint() {  
        return new EchoEndpoint(echoService());  
      }  
      
      @Bean  
      public EchoService echoService() {  
        // ...  
      }  
      
      @Bean  
      public ServerEndpointExporter endpointExporter() {  
        return new ServerEndpointExporter();  
      }  
      
    }  

 EchoEndpoint can be published via EndPointRegistration:

    import org.springframework.web.socket.server.endpoint.ServerEndpointExporter;  
    import org.springframework.web.socket.server.endpoint.ServerEndpointRegistration;  
      
      
    @Configuration  
    public class EndpointConfig {  
      
      @Bean  
      public EndpointRegistration echoEndpoint() {  
        return new EndpointRegistration("/echo", EchoEndpoint.class);  
      }  
      
      @Bean  
      public ServerEndpointExporter endpointExporter() {  
        return new ServerEndpointExporter();  
      }  
      
      // ..  
      
    }  

 The source code of this example: spring-websocket-test-endpoint.zip

2、Spring WebSocket API

Spring WebSocket API provides support for SockJS, and some containers such as Jetty 9 currently do not support JSR-356, so it is necessary to have Spring WebSocket API.

 

The core interface of Spring WebSocket API is WebSocketHandler. The following is an implementation of a handler that handles text messages:

import org.springframework.web.socket.adapter.TextWebSocketHandlerAdapter;


public class EchoHandler extends TextWebSocketHandlerAdapter {

  @Override
  public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    session.sendMessage(message);
  }

}

WebSocketHandler can be inserted into Spring MVC via WebSocketHttpRequestHandler:

import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;


@Configuration
public class WebConfig {

  @Bean
  public SimpleUrlHandlerMapping handlerMapping() {

    Map<String, Object> urlMap = new HashMap<String, Object>();
    urlMap.put("/echo", new WebSocketHttpRequestHandler(new EchoHandler()));

    SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();
    hm.setUrlMap(urlMap);
    return hm;
  }

}

 SockJS server-side support

SockJs is a scripting framework that provides a programming mode similar to websocket but can be adapted to different browsers (including browsers that do not support websocket).

 

Enable SockJS support, declare a SockJsService, and a url mapping, and then provide a WebSocketHandler to process messages. Although we are a SockJS, our development method is the same, but the transmission protocol can be Http Streaming, long polling, etc. depending on the browser.

import org.springframework.web.socket.sockjs.SockJsService;
// ...


@Configuration
public class WebConfig {

  @Bean
  public SimpleUrlHandlerMapping handlerMapping() {

    SockJsService sockJsService = new DefaultSockJsService(taskScheduler());

    Map<String, Object> urlMap = new HashMap<String, Object>();
    urlMap.put("/echo/**", new SockJsHttpRequestHandler(sockJsService, new EchoHandler()));

    SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();
    hm.setUrlMap(urlMap);
    return hm;
  }

  @Bean
  public ThreadPoolTaskScheduler taskScheduler() {
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.setThreadNamePrefix("SockJS-");
    return taskScheduler;
  }

}

In our actual use, we will use WebSocketConfigurer to centrally register WebSocket services:

@Configuration
@EnableWebMvc
@EnableWebSocket//开启websocket
public class WebConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {

	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

		registry.addHandler(echoWebSocketHandler(), "/echo"); //提供符合W3C标准的Websocket数据
		registry.addHandler(snakeWebSocketHandler(), "/snake");

		registry.addHandler(echoWebSocketHandler(), "/sockjs/echo").withSockJS();//提供符合SockJS的数据
		registry.addHandler(snakeWebSocketHandler(), "/sockjs/snake").withSockJS();
	}

	@Bean
	public WebSocketHandler echoWebSocketHandler() {
		return new EchoWebSocketHandler(echoService());
	}

	@Bean
	public WebSocketHandler snakeWebSocketHandler() {
		return new PerConnectionWebSocketHandler(SnakeWebSocketHandler.class);
	}

	@Bean
	public DefaultEchoService echoService() {
		return new DefaultEchoService("Did you say \"%s\"?");
	}

	// Allow serving HTML files through the default Servlet

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}

}

SockJS client code:

ws = new SockJS(url, undefined, {protocols_whitelist: transports}) ;   //初始化 websocket
         
ws.onopen = function () {
                setConnected(true);
                log('Info: connection opened.');
            };

ws.onmessage = function (event) {
                log('Received: ' + event.data); //处理服务端返回消息
            };

ws.onclose = function (event) {
                setConnected(false);
                log('Info: connection closed.');
                log(event);
            };

 ws.send(message);//向服务端发送消息

 After the program is made into war with maven, it is published with tomcat 8 to view the effect.

Source code of this example: spring-websocket-test-master.zip

Original article address: http://wiselyman.iteye.com/blog/2003336

Guess you like

Origin blog.csdn.net/huanglgln/article/details/46571995