The following tutorial is a crm system of the company that I participated in the development of a company, and sorted out some relevant information. There are many message push functions in the system, and websocket technology is used in it. The following editor compiled and shared it on the Wulin Network platform for your reference
1. maven dependency
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson -databind</artifactId><version>2.3.0</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>4.0.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-messaging</artifactId><version>4.0.1.RELEASE</version></dependency>
2. Spring-servlet configuration
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:websocket="http://www.springframework.org/schema/websocket"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/context/spring -context-3.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.1.xsdhttp://www.springframework.org/schema/txhttp://www.spr ingframework.org/schema/tx/spring-tx-3.1.xsdhttp://www.springframework.org/schema/websocketthttp://www.springframework.org/schema/websocket/spring-websocket.xsd">.........<!-- websocket --><bean id="websocket"/><websocket:handlers><websocket:mapping path="/websocket" handler="websocket"/><websocket:handshake-interceptors><bean/><websocket:handshake-interceptors></websocket:handlers></beans>
Among them, the path corresponding to path is the interface path that was tuned through the WS protocol in the previous section.
3. Implementation of HandshakeInterceptor
package cn.bridgeli.websocket;import cn.bridgeli.utils.UserManager;import cn.bridgeli.util.DateUtil;import cn.bridgeli.sharesession.UserInfo;import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;import java.util.Date;import java.util.Map;/*** @Description :Create a handshake interface* @Date: 16-3-3*/public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor{private static final Logger logger = LoggerFactory.getLogger(HandshakeInterceptor.class);@Overridepublic boolean beforeHandshake(ServerHttpRequest request,ServerHttpResponse response, WebSocketHandler wsHandler,Map<String, Object> attributes) throws Exception {logger.info("Before creating handshake...");ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();UserInfo currUser = UserManager.getSessionUser(attrs.getRequest());UserSocketVo userSocketVo = new UserSocketVo();String email= "";if(null != currUser){email = currUser.getEmail();}if(StringUtils.isBlank(email)){email = DateUtil.date2String(new Date());}userSocketVo.setUserEmail(email); attributes.put("SESSION_USER", userSocketVo); return super.beforeHandshake(request, response, wsHandler, attributes);}@Overridepublic void afterHandshake(ServerHttpRequest request,ServerHttpResponse response, WebSocketHandler wsHandler,Exception ex) {logger.info("After creating handshake...");super.afterHandshake(request, response, wsHandler, ex);}}Because I don't understand very well, I keep the original code to the maximum extent. This is actually to take out the current login user from single sign-in, convert it into a UserSocketVo object, and put it in the map. So let's take a look at the definition of the UserSocketVo object
4. Definition of UserSocketVo
package cn.bridgeli.websocket;import org.springframework.web.socket.WebSocketSession;import java.util.Date;/*** @Description : User socket connection entity* @Date : 16-3-7*/public class UserSocketVo {private String userEmail; //User email private Date connectionTime; //Successful connection time private Date preRequestTime; //Last request time private Date newRequestTime; //New request time private Date lastSendTime = new Date(); //The last sending time of the removal message private Date lastTaskSendTime = new Date(); //The last sending time of the pending task private WebSocketSession webSocketSession; //The wsSession corresponding to the user only caches one by default // getXX and setXX }The most important one is the WebSocketSession property, which we will use later
5. Implementation of WebsocketEndPoint
package cn.bridgeli.websocket;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.socket.CloseStatus;import org.springframework.web.socket.TextMessage;import org.springframework.web.socket.WebSocketSession;import org.springframework.web.socket.handler.TextWebSocketHandler;/*** @Description : websocket processing class* @Date : 16-3-3*/public class WebsocketEndPoint extends TextWebSocketHandler{private static final Logger logger = LoggerFactory.getLogger(WebsocketEndPoint.class);@Autowiredprivate NewsListenerImpl newsListener;@Overrideprotected void handleTextMessage(WebSocketSession session,TextMessage message) throws Exception {super.handleTextMessage(session, message);TextMessage returnMessage = new TextMessage(message.getPayload()+" received at server");session.sendMessage(returnMessage);}/*** @Description : After establishing the connection* @param session* @throws Exception*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception{UserSocketVo userSocketVo = (UserSocketVo)session.getAttributes().get("SESSION_USER"); if(null != userSocketVo){userSocketVo.setWebSocketSession(session); if(WSSessionLocalCache.exists(userSocketVo.getUserEmail())){WSSessionLocalCache.remove(userSocketVo.getUserEmail());}WSSessionLocalCache.put(userSocketVo.getUserEmail(), userSocketVo);newsListener.afterConnectionEstablished(userSocketVo.getUserEmail());}logger.info("socket successfully established connection...");super.afterConnectionEstablished(session);}@Overridepublic void afterConnectionClosed(WebSocketSession session,CloseStatus status) throws Exception{UserSocketVo userSocketVo = (UserSocketVo)session.getAttributes().get("SESSION_USER");if(null != userSocketVo){WSSessionLocalCache.remove(userSocketVo.getUserEmail());}logger.info("socket successfully closed the connection...");super.afterConnectionClosed(session, status);}}6. Implementation of WSSessionLocalCache
package cn.bridgeli.websocket;import java.io.Serializable;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/*** @Description : Local cache WebSocketSession instance* @Date : 16-3-7*/public class WSSessionLocalCache implements Serializable {private static Map<String, UserSocketVo> wsSessionCache = new HashMap<>();public static boolean exists(String userEmail){if(!wsSessionCache.containsKey(userEmail)){return false;}else{return true;}}public static void put(String userEmail, UserSocketVo UserSocketVo){wsSessionCache.put(userEmail, UserSocketVo);}public static UserSocketVo get(String userEmail){return wsSessionCache.get(userEmail);}public static void remove(String userEmail){wsSessionCache.remove(userEmail);}public static List<UserSocketVo> getAllSessions(){return new ArrayList<>(wsSessionCache.values());}}After looking at its implementation, the effect is more obvious. It stores the latest data of each UserSocketVo. In fact, our websocket implementation has been calculated here, but there is still a core class (Charlie's class about business logic) that has not been implemented. In the next article, Spring integrated WebSocket application example (Part 2), we will see how to implement this class.
Introduction to WebSocket protocol
The WebSocket protocol is an important function in the Web field defined by the RFC-6455 specification: full duplex, that is, two-way communication between the client and the server. It is an exciting feature. The industry has been exploring this field for a long time. The technologies used include Java Applet, XMLHttpRequest, Adobe Flash, ActiveXObject, various Comet technologies, server-side sending events, etc.
It should be understood that before using the WebSocket protocol, you need to use the HTTP protocol to build the initial handshake. This relies on a mechanism - establishing HTTP and requesting protocol upgrades (or protocol conversions). When the server agrees, it will respond to the HTTP status code 101, indicating that it agrees to switch the protocol. Assuming that a successful handshake through TCP sockets and the HTTP protocol upgrade request is passed, then both the client and the server can send messages to each other.
Spring Framework 4.0 and above introduced a new module, namely the spring-websocket module. It provides support for WebSocket communication. It is compatible with the Java WebSocket API specification JSR-356, while providing additional functionality.
In what scenario should you use WebSocket
In web applications, when the client and server need to exchange events with higher frequency and lower latency, it is suitable for WebSocket. Therefore, WebSocket is suitable for application scenarios such as finance, gaming, and collaboration.
It may not be suitable for other application scenarios. For example, a news subscription requires breaking news to be displayed, and it is also OK to use a long polling of several minutes apart, and the delay here is acceptable.
Even in applications where low latency is required, if the number of messages transmitted is very low (such as those monitoring network failures), long polling technology should be considered.
Only in scenarios with low latency and high frequency message communication, choosing the WebSocket protocol is very suitable. Even in such an application scenario, is it still possible to choose WebSocket communication? Or choose REST HTTP communication?
The answer is that it will depend on the needs of the application. However, it is also possible to use these two technologies at the same time to put data that needs to be frequently exchanged into WebSocket, and use the REST API as a process-based business implementation technology. In addition, when a certain information needs to be broadcast to multiple clients in the REST API call, it can also be implemented through WebSocket connection.
The Spring framework provides @Controller annotation and @RestController annotation, both of which can be used for the processing of HTTP requests and the processing of WebSocket messages. In addition, Spring MVC request processing methods, or other application request processing methods, can easily use the WebSocket protocol to broadcast messages to all interested clients or designated users.