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);
            }
        }
    }
}

 

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