Spring Cloud Microservices Using webSocket
- 2021-10-11 18:43:52
- OfStack
webSocket
webSocket Long Connection is a protocol for full duplex communication over a single tcp connection, allowing bidirectional data push. 1 restful API provided by microservices only respond to front-end requests. Using webSocket, the back end can actively push messages to the front end.
Gateway configuration
The gateway components of spring cloud are zuul and getway
getway
base:
config:
nacos:
nacoshost: localhost
port: 8848
spring:
application:
name: gateway
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
server-addr: ${base.config.nacos.nacoshost}:${base.config.nacos.port}
gateway:
discovery:
locator:
enabled: true
routes:
# websocket
- id: CLOUD-WEBSOCKET
uri: lb:ws://cloud-websocket
predicates:
- Path=/cloud-websocket/**
server:
port: 8888
Pay attention to adding ws protocol when configuring gateway.
zuul
zuul can only manage http requests. zuul is not recommended to manage websocket connections. Direct connection is recommended.
Server side
Add an maven dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
Add webSocket configuration
@Configuration
@EnableWebSocket
public class WebsocketConfiguration implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// webSocket Channel
// Specify the processor and path
registry.addHandler(new WebSocketHandler(), "/websocket")
// Specify a custom interceptor
.addInterceptors(new WebSocketInterceptor())
// Allow cross-domain
.setAllowedOrigins("*");
// sockJs Channel
registry.addHandler(new WebSocketHandler(), "/sock-js")
.addInterceptors(new WebSocketInterceptor())
.setAllowedOrigins("*")
// Open sockJs Support
.withSockJS();
}
}
Add processor
package com.auexpress.cloud.handler;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Description
* @ClassName WebSocketHandler
* @Author HYSong
* @date 2020.04.14 10:08
*/
public class WebSocketHandler extends AbstractWebSocketHandler {
/**
* Storage sessionId And webSocketSession
* It should be noted that, webSocketSession No parameterless construction is provided, so it cannot be serialized, and it cannot be passed through redis Storage
* In a distributed system, if you want to find other ways to achieve it, webSocketSession Sharing
*/
private static Map<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
private static Map<String, String> userMap = new ConcurrentHashMap<>();
/**
* webSocket Called after the connection is created
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) {
// Get parameters
String user = String.valueOf(session.getAttributes().get("user"));
userMap.put(user, session.getId());
sessionMap.put(session.getId(), session);
}
/**
* When a message is received, it calls
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
JSONObject jsonObject = JSONObject.parseObject(message.getPayload().toString());
String content = jsonObject.getString("content");
String targetAdminId = jsonObject.getString("targetId");
if("0".equals(targetAdminId)){
// Push it to everyone
userMap.forEach((key,value)->{
try {
this.sendMessage(key,content);
} catch (IOException e) {
e.printStackTrace();
}
});
}else{
sendMessage("1", content);
}
}
/**
* A connection error calls the
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) {
sessionMap.remove(session.getId());
}
/**
* Connection closure calls
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessionMap.remove(session.getId());
}
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* Back-end sending messages
*/
public void sendMessage(String user, String message) throws IOException {
String sessionId = userMap.get(user);
if (StringUtils.isEmpty(sessionId)) {
return;
}
WebSocketSession session = sessionMap.get(sessionId);
if (session == null) {
return;
}
session.sendMessage(new TextMessage(message));
}
}
Add an interceptor
package com.auexpress.cloud.interceptor;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
import java.util.Map;
/**
* @Description
* @ClassName WebSocketInterceptor
* @Author HYSong
* @date 2020.04.14 10:09
*/
public class WebSocketInterceptor implements HandshakeInterceptor {
/**
* handler Called before processing ,attributes Property ends up in the WebSocketSession Li ,
* Possibly through webSocketSession.getAttributes().get(key Value ) Obtain
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
// Gets the parameters carried by the request path
String user = serverHttpRequest.getServletRequest().getParameter("user");
attributes.put("user", user);
return true;
} else {
return false;
}
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
}
}