WebSocket+spring example demo (sockJs library has been used)

  • 2020-06-01 09:41:36
  • OfStack

1, the introduction of

As the next generation of the Web standard, HTML5 has many compelling new features, such as Canvas, local storage, multimedia programming interfaces, WebSocket, and so on. Among them, WebSocket, known as "TCP of Web", attracts developers' attention. The advent of WebSocket makes it possible for browsers to provide support for Socket, providing a two-way channel between the browser and the server based on an TCP connection. Web developers can easily use WebSocket to build real-time web applications, giving them an extra weapon in their hands.

Web application information interaction process is usually the client through the browser sends a request to the server after receive and review the request and returns the result to the client, the client browser will then display information, this mechanism for information change is not particularly frequent application is easy, but for those requiring real-time applications, such as online games, online security, equipment monitoring, news online, RSS subscription push, etc., when the client browser ready to present this information, the information on the server side may have already out of date.

Therefore, keeping the information on the client side and the server side synchronized is a key element of real-time Web application, which is also a challenge for Web developers. Before the WebSocket specification came out, developers who wanted to implement these real-time Web applications had to adopt a number of tradeoffs, among which the most commonly used were polling (Polling) and Comet technologies. Comet technology is actually an improvement on polling technology, which can be subdivided into two implementations, one is a long polling mechanism, and one is called flow technology.

Html5 WebSocket is designed to replace polling and Comet technologies, giving the client browser the ability to communicate in real time like C/S desktops. The browser sends a request to the server via JavaScript to establish an WebSocket connection. Once the connection is established, the client and server can exchange data directly via the TCP connection. Because an WebSocket connection is essentially an TCP connection, it has a significant performance advantage over polling and Comet technologies in terms of data transmission stability and the amount of data transferred.

However, because web socket has high requirements for browsers, to solve this problem, sockJS was launched. SockJS is a library of JavaScript that provides API across javascript, creating a communication channel between a low-latency, full-duplex browser and web server.

2. Related environmental requirements

Spring4.0.6 (select 4.0+), tomcat7.0.55, JDK1.7.

3. Specific code

(the following code is available!)

(1) web. xml:


<?xmlversionxmlversion="1.0"encoding="UTF-8"?> 
<web-app version="3.1" 
xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> 
 <description> Used to test WebSocket Push based functionality </description> 
 <distributable/> 
 <filter> 
  <filter-name>encodingFilter</filter-name> 
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 
  <async-supported>true</async-supported> 
  <init-param> 
   <param-name>encoding</param-name> 
   <param-value>UTF-8</param-value> 
  </init-param> 
  <init-param> 
   <param-name>forceEncoding</param-name> 
   <param-value>true</param-value> 
  </init-param>  
 </filter> 
 <filter-mapping> 
  <filter-name>encodingFilter</filter-name> 
  <url-pattern>/*</url-pattern> 
 </filter-mapping> 
 <listener> 
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
 </listener> 
 <!-- Spring  The refresh Introspector Prevent memory leaks  --> 
 <listener> 
  <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> 
 </listener> 
 <servlet> 
  <servlet-name>dispatcher</servlet-name> 
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  <init-param> 
  <param-name>contextConfigLocation</param-name> 
  <param-value>classpath:dispatcher-servlet.xml</param-value> 
  </init-param> 
  <load-on-startup>1</load-on-startup> 
  <async-supported>true</async-supported> 
 </servlet> 
 <servlet-mapping> 
  <servlet-name>dispatcher</servlet-name> 
  <url-pattern>/</url-pattern> 
 </servlet-mapping> 
 <session-config> 
  <session-timeout> 
   30 
  </session-timeout> 
 </session-config> 
 <welcome-file-list> 
  <welcome-file>testSocket.jsp</welcome-file> 
 </welcome-file-list> 
</web-app> 

(2) dispatcher-servlet.xml


<?xmlversionxmlversion="1.0"encoding="UTF-8"?> 
<beans:beansxmlnsbeans:beansxmlns="http://www.springframework.org/schema/mvc" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:beans="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd 
 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 
 <annotation-driven/> 
 <!--  Automatically scanned package name  --> 
 <context:component-scanbase-packagecontext:component-scanbase-package="zyy.sockjs.config"></context:component-scan> 
</beans:beans> 

(3)HandshakeInterceptor.java


package zyy.sockjs.config; 
import java.util.Map; 
import org.springframework.http.server.ServerHttpRequest; 
import org.springframework.http.server.ServerHttpResponse; 
import org.springframework.stereotype.Component; 
import org.springframework.web.socket.WebSocketHandler; 
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; 
 
@Component 
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor { 
@Override 
public boolean beforeHandshake(ServerHttpRequest request, 
 ServerHttpResponse response, WebSocketHandler wsHandler, 
 Map<String, Object> attributes) throws Exception { 
 System.out.println("Before Handshake"); 
 return super.beforeHandshake(request,response,wsHandler,attributes); 
} 
 
@Override 
public void afterHandshake(ServerHttpRequest request, 
 ServerHttpResponse response, WebSocketHandler wsHandler, 
 Exception ex) { 
 System.out.println("After Handshake"); 
 super.afterHandshake(request,response,wsHandler,ex); 
} 
} 

(4)InfoSocketEndPoint.Java


package zyy.sockjs.config; 
import org.springframework.stereotype.Component; 
import org.springframework.web.socket.TextMessage; 
import org.springframework.web.socket.WebSocketSession; 
import org.springframework.web.socket.handler.TextWebSocketHandler; 
 
@Component 
public class InfoSocketEndPoint extends TextWebSocketHandler { 
public InfoSocketEndPoint() { 
} 
 
@Override 
protected void handleTextMessage(WebSocketSession session, 
 TextMessage message) throws Exception { 
 super.handleTextMessage(session, message); 
 TextMessage returnMessage = new TextMessage(message.getPayload() 
 + " received at server"); 
 session.sendMessage(returnMessage); 
} 
} 

(5)SystemWebSocketHandler.java


package zyy.sockjs.config; 
import org.springframework.stereotype.Component; 
import org.springframework.web.socket.CloseStatus; 
import org.springframework.web.socket.TextMessage; 
import org.springframework.web.socket.WebSocketHandler; 
import org.springframework.web.socket.WebSocketMessage; 
import org.springframework.web.socket.WebSocketSession; 
/** 
* 
* @author dayu 
*/ 
 
@Component 
public class SystemWebSocketHandler implements WebSocketHandler { 
 @Override 
 public void afterConnectionEstablished(WebSocketSession session) throws Exception { 
  System.out.println("connect to the websocket success......"); 
  session.sendMessage(new TextMessage("Server:connected OK!")); 
 } 
 
 @Override 
 public void handleMessage(WebSocketSession wss, WebSocketMessage<?> wsm) throws Exception { 
  TextMessage returnMessage = new TextMessage(wsm.getPayload() 
  + " received at server"); 
  wss.sendMessage(returnMessage); 
 } 
 
 @Override 
 public void handleTransportError(WebSocketSession wss, Throwable thrwbl) throws Exception { 
  if(wss.isOpen()){ 
   wss.close(); 
  } 
  System.out.println("websocket connection closed......"); 
 } 
 
 @Override 
 public void afterConnectionClosed(WebSocketSession wss, CloseStatus cs) throws Exception { 
  System.out.println("websocket connection closed......"); 
 } 
 
 @Override 
 public boolean supportsPartialMessages() { 
  return false; 
 } 
} 

(6)WebSocketConfig.java


package zyy.sockjs.config; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.web.servlet.config.annotation.EnableWebMvc; 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 
import org.springframework.web.socket.WebSocketHandler; 
import org.springframework.web.socket.config.annotation.EnableWebSocket; 
import org.springframework.web.socket.config.annotation.WebSocketConfigurer; 
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; 
 
@Configuration 
@EnableWebMvc 
@EnableWebSocket 
public class WebSocketConfig extends WebMvcConfigurerAdapter implements 
  WebSocketConfigurer { 
 public WebSocketConfig() { 
 } 
 
 @Override 
 public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { 
  registry.addHandler(systemWebSocketHandler(), "/websck").addInterceptors(new HandshakeInterceptor()); 
  System.out.println("registed!"); 
  registry.addHandler(systemWebSocketHandler(), "/sockjs/websck/info").addInterceptors(new HandshakeInterceptor()) 
    .withSockJS(); 
 } 
 
 @Bean 
 public WebSocketHandler systemWebSocketHandler() { 
  return new SystemWebSocketHandler(); 
 } 
} 

(7)testSocket.jsp


<%@ page language="java"contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> 
<!DOCTYPE htmlPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
<meta http-equiv="Content-Type"content="text/html; charset=ISO-8859-1"> 
<title>WebSocket/SockJS Echo Sample (Adapted from Tomcat's echo sample)</title> 
 <style type="text/css"> 
  #connect-container { 
   float: left; 
   width: 400px 
  } 
  #connect-container div { 
   padding: 5px; 
  } 
  #console-container { 
   float: left; 
   margin-left: 15px; 
   width: 400px; 
  } 
  #console { 
   border:1px solid #CCCCCC; 
   border-right-color:#33333333; 
   border-bottom-color:#999999; 
   height: 170px; 
   overflow-y: scroll; 
   padding: 5px; 
   width: 100%; 
  } 
  #console p { 
   padding: 0; 
   margin: 0; 
  } 
 </style> 
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script> 
<script type="text/javascript"> 
  var ws = null; 
  var url = null; 
  var transports = []; 
  function setConnected(connected) { 
   document.getElementById('connect').disabled = connected; 
   document.getElementById('disconnect').disabled = !connected; 
   document.getElementById('echo').disabled = !connected; 
  } 
  function connect() { 
   if (!url) {    
   log('Select whether to use W3C WebSocket or SockJS');    
    return; 
   } 
   //ws = (url.indexOf('sockjs') != -1) ?new SockJS(url, undefined, {protocols_whitelist: transports}) : new WebSocket(url); 
   if ('WebSocket'in window) { 
    ws= new WebSocket("ws://localhost:8080/SpringSocketJs/websck"); 
   }else { 
    ws = new SockJS("http://localhost:8080/SpringSocketJs/sockjs/websck/info"); 
   } 
   //websocket = new SockJS("http://localhost:8084/SpringWebSocketPush/sockjs/websck"); 
   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); 
   }; 
  } 
  function disconnect() { 
   if (ws != null) { 
    ws.close(); 
    ws = null; 
   } 
   setConnected(false); 
  } 
  function echo() { 
   if (ws != null) { 
    var message = document.getElementById('message').value; 
    log('Sent: ' + message); 
    ws.send(message); 
   } else { 
    alert('connection not established, please connect.'); 
   } 
  } 
  function updateUrl(urlPath) { 
   if (urlPath.indexOf('sockjs') != -1) { 
    url = urlPath; 
    document.getElementById('sockJsTransportSelect').style.visibility ='visible'; 
   } 
   else { 
    if (window.location.protocol =='http:') { 
     url = 'ws://' + window.location.host + urlPath; 
    } else { 
     url = 'wss://' + window.location.host + urlPath; 
    } 
    document.getElementById('sockJsTransportSelect').style.visibility ='hidden'; 
   } 
  } 
  function updateTransport(transport) { 
   transports = (transport == 'all') ? [] : [transport]; 
  }  
  function log(message) { 
   var console = document.getElementById('console'); 
   var p = document.createElement('p'); 
   p.style.wordWrap = 'break-word'; 
   p.appendChild(document.createTextNode(message)); 
   console.appendChild(p); 
   while (console.childNodes.length > 25) { 
    console.removeChild(console.firstChild); 
   } 
   console.scrollTop = console.scrollHeight; 
  } 
 </script> 
</head> 
<body> 
<noscript><h2 style="color:#ff0000">Seems your browser doesn't supportJavascript!Websockets 
 rely on Javascript being enabled. Please enable 
 Javascript and reload this page!</h2></noscript> 
<div> 
 <div id="connect-container"> 
  <input id="radio1"type="radio"name="group1"onclick="updateUrl('/SpringSocketJs/websocket');"> 
   <label for="radio1">W3C WebSocket</label> 
  <br> 
  <input id="radio2"type="radio"name="group1"onclick="updateUrl('/SpringSocketJs/sockjs/websocket');"> 
   <label for="radio2">SockJS</label> 
  <div id="sockJsTransportSelect" style="visibility:hidden;"> 
   SockJS transport: 
   <select onchange="updateTransport(this.value)"> 
    <option value="all">all</option> 
    <option value="websocket">websocket</option> 
    <option value="xhr-polling">xhr-polling</option> 
    <option value="jsonp-polling">jsonp-polling</option> 
    <option value="xhr-streaming">xhr-streaming</option> 
    <option value="iframe-eventsource">iframe-eventsource</option> 
    <option value="iframe-htmlfile">iframe-htmlfile</option> 
   </select> 
  </div> 
  <div> 
   <button id="connect"onclick="connect();">Connect</button> 
   <button id="disconnect"disabled="disabled"onclick="disconnect();">Disconnect</button> 
  </div> 
  <div> 
   <textarea id="message"style="width:350px">Here is a message!</textarea> 
  </div> 
  <div> 
   <button id="echo"onclick="echo();"disabled="disabled">Echo message</button> 
  </div> 
 </div> 
 <div id="console-container"> 
  <div id="console"></div> 
 </div> 
</div> 
</body> 
</html> 

Related articles: