简介: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);
}
}
}
}