簡介:websocket是基於TCP的全雙工長連接協議,http發起請求,tcp握手創建連接。如下代碼 基於springboot,服務端簡易demo
1、導入pom依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</exclusion>
</exclusions>
</dependency>
2、引入websocket註解bean掃描器
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
/**
* 注入一個ServerEndpointExporter,該Bean會自動註冊使用@ServerEndpoint註解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3、發佈簡易服務
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
/**
* 前後端交互的類實現消息的接收推送(自己發送給自己)
*
*/
@Slf4j
@Component
@ServerEndpoint(value = "/test/ysma")
public class WebSocketFadeServer {
/**
* 連接建立成功調用的方法
*/
@OnOpen
public void onOpen(Session session) {
log.info("連接加入, sessionId:{}", session.getId());
}
/**
* 連接關閉調用的方法
*/
@OnClose
public void onClose(Session session) {
log.info("連接關閉,sessionId:{}", session.getId());
}
/**
* 收到客戶端消息後調用的方法
*
* @param message 客戶端發送過來的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("服務端收到客戶端[{}]的消息:{}", session.getId(), message);
this.sendMessage("Hello, " + message, session);
}
@OnError
public void onError(Session session, Throwable error) {
log.error("會話【{}】發生錯誤", session.getId(), error);
}
/**
* 服務端發送消息給客戶端
*/
private void sendMessage(String message, Session session) {
try {
log.info("服務端給客戶端[{}]發送消息{}", session.getId(), message);
session.getBasicRemote().sendText("你好,消息我收到了,msg:" + message);
} catch (Exception e) {
log.error("服務端發送消息給客戶端失敗", e);
}
}
}
4、註解客戶端
import lombok.extern.slf4j.Slf4j;
import javax.websocket.ClientEndpoint;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TransferQueue;
/**
* Description websocket client
* Date 2021/11/9 13:23
*
* @author by mays
*/
@Slf4j
@ClientEndpoint
public class WebSocketClient {
public static Map<String, TransferQueue<String>> sessionMap = new ConcurrentHashMap<>();
@OnOpen
public void opOpen(Session session) {
log.info("客戶端發起連接,sessionId:{}", session.getId());
sessionMap.put(session.getId(), new LinkedTransferQueue<>());
}
@OnMessage
public void onMessage(String msg, Session session) {
boolean offer = sessionMap.get(session.getId()).offer(msg);
log.info("客戶端收到響應,sessionId:{}, msg:{}, offer:{}", session.getId(), msg, offer);
}
@OnClose
public void close(Session session) {
log.info("客戶端連接關閉,sessionId:{}", session.getId());
sessionMap.remove(session.getId());
}
@OnError
public void onError(Session session, Throwable error) {
log.error("會話【{}】發生錯誤", session.getId(), error);
}
/**
*
* @param sessionId 會話id
* @param second 超時秒數 默認1s
* @return resp msg
*/
public static Response<?> getMsg(String sessionId, long... second) throws InterruptedException {
if(sessionMap.containsKey(sessionId)) {
long timeout = second.length > 0 ? second[0] : 3;
String respMsg = sessionMap.get(sessionId).poll(timeout, TimeUnit.SECONDS);
return respMsg ;
} else {
log.error("會話id:{} 不存在或已被銷燬", sessionId);
return Response.createError("會話id:" + sessionId + " 不存在或已被銷燬");
}
}
}
5、創建客戶端工廠
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Description 客戶端連接工廠
* Date 2021/11/9 13:38
*
* @author by mays
*/
@Slf4j
public class WebsocketClientFactory {
public static Session getSession(String url, HttpHeaders... headers) {
URI uri = URI.create(url);
WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
Session session = null;
try {
ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create();
builder.configurator(new ClientEndpointConfig.Configurator(){
@Override
public void beforeRequest(Map<String, List<String>> requestHeaders) {
if(headers != null && headers.length > 0) {
requestHeaders.putAll(headers[0]);
}
super.beforeRequest(requestHeaders);
}
});
session = webSocketContainer.connectToServer(WebSocketClient.class, uri);
} catch (DeploymentException | IOException e) {
log.error("連接服務端:{}失敗", url, e);
} catch (Exception e) {
log.error("連接服務端:{}異常", url, e);
}
return session;
}
public static void closeSession(Session session) {
if(Objects.nonNull(session)) {
try {
session.close();
} catch (IOException e) {
log.error("session連接:{}關閉失敗", session.getId(), e);
} catch (Exception e) {
log.error("session連接:{}關閉異常", session.getId(), e);
}
}
}
}