Springboot 微服务之 Websocket

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章