真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

SpringBoot跟WebSocket的開發(fā)過程是怎樣的

SpringBoot跟WebSocket的開發(fā)過程是怎樣的,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

創(chuàng)新互聯(lián)公司致力于互聯(lián)網(wǎng)網(wǎng)站建設(shè)與網(wǎng)站營銷,提供網(wǎng)站建設(shè)、成都做網(wǎng)站、網(wǎng)站開發(fā)、seo優(yōu)化、網(wǎng)站排名、互聯(lián)網(wǎng)營銷、重慶小程序開發(fā)、公眾號商城、等建站開發(fā),創(chuàng)新互聯(lián)公司網(wǎng)站建設(shè)策劃專家,為不同類型的客戶提供良好的互聯(lián)網(wǎng)應(yīng)用定制解決方案,幫助客戶在新的全球化互聯(lián)網(wǎng)環(huán)境中保持優(yōu)勢。

1. 服務(wù)端的實(shí)現(xiàn),我嘗試了兩種方式:

  • 第一種是用“@ServerEndPoint”注解來實(shí)現(xiàn),實(shí)現(xiàn)簡單;

  • 第二種稍顯麻煩,但是可以添加攔截器在WebSocket連接建立和斷開前進(jìn)行一些額外操作。

不管用哪種實(shí)現(xiàn)方式,都需要先導(dǎo)入jar包(如下),其中version根據(jù)實(shí)際springboot版本選擇,避免沖突


    org.springframework.boot
    spring-boot-starter-websocket
    

1.1 第一種實(shí)現(xiàn)方法

(1)WebSocket 業(yè)務(wù)邏輯實(shí)現(xiàn)。參數(shù)傳遞采用路徑參數(shù)的方法,通過以下方式獲取參數(shù):

  • @ServerEndpoint("/testWebSocket/{id}/{name}")

  • public void onOpen(Session session, @PathParam("id") long id, @PathParam("name") String name)

import java.util.concurrent.CopyOnWriteArraySet;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestController;
@ServerEndpoint("/testWebSocket/{id}/{name}")
@RestController
public class TestWebSocket {
    // 用來記錄當(dāng)前連接數(shù)的變量
    private static volatile int onlineCount = 0;
    // concurrent包的線程安全Set,用來存放每個客戶端對應(yīng)的MyWebSocket對象
    private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();
    // 與某個客戶端的連接會話,需要通過它來與客戶端進(jìn)行數(shù)據(jù)收發(fā)
    private Session session;
    private static final Logger LOGGER = LoggerFactory.getLogger(TestWebSocket.class);
      @OnOpen
    public void onOpen(Session session, @PathParam("id") long id, @PathParam("name") String name) throws Exception {
        this.session = session;
        System.out.println(this.session.getId());
        webSocketSet.add(this);
        LOGGER.info("Open a websocket. id={}, name={}", id, name);
    }
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        LOGGER.info("Close a websocket. ");
    }
    @OnMessage
    public void onMessage(String message, Session session) {
        LOGGER.info("Receive a message from client: " + message);
    }
    @OnError
    public void onError(Session session, Throwable error) {
        LOGGER.error("Error while websocket. ", error);
    }
    public void sendMessage(String message) throws Exception {
        if (this.session.isOpen()) {
            this.session.getBasicRemote().sendText("Send a message from server. ");
        }
    }
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    public static synchronized void addOnlineCount() {
        TestWebSocket.onlineCount++;
    }
    public static synchronized void subOnlineCount() {
        TestWebSocket.onlineCount--;
    }
}

(2)配置ServerEndpointExporter,配置后會自動注冊所有“@ServerEndpoint”注解聲明的Websocket Endpoint

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
@Configuration
public class WebSocketConfig {
 
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
 
}

1.2 第二種實(shí)現(xiàn)方法

(1)WebSocket 業(yè)務(wù)邏輯實(shí)現(xiàn)。參數(shù)傳遞采用類似GET請求的方式傳遞,服務(wù)端的參數(shù)在攔截器中獲取之后通過attributes傳遞給WebSocketHandler。

import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
 
@RestController
public class TestWebSocketController implements WebSocketHandler {
 
    private static AtomicInteger onlineCount = new AtomicInteger(0);
 
    private static final ArrayList sessions = new ArrayList<>();
 
    private final Logger LOGGER = LoggerFactory.getLogger(TestWebSocketController.class);
 
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session);
        int onlineNum = addOnlineCount();
        LOGGER.info("Oprn a WebSocket. Current connection number: " + onlineNum);
    }
 
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessions.remove(session);
        int onlineNum = subOnlineCount();
        LOGGER.info("Close a webSocket. Current connection number: " + onlineNum);
    }
 
    @Override
    public void handleMessage(WebSocketSession wsSession, WebSocketMessage message) throws Exception {
        LOGGER.info("Receive a message from client: " + message.toString());
    }
 
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        LOGGER.error("Exception occurs on webSocket connection. disconnecting....");
        if (session.isOpen()) {
            session.close();
        }
        sessions.remove(session);
        subOnlineCount();
    }
 
    /*
     * 是否支持消息拆分發(fā)送:如果接收的數(shù)據(jù)量比較大,最好打開(true), 否則可能會導(dǎo)致接收失敗。
     * 如果出現(xiàn)WebSocket連接接收一次數(shù)據(jù)后就自動斷開,應(yīng)檢查是否是這里的問題。
     */
    @Override
    public boolean supportsPartialMessages() {
        return true;
    }
 
    public static int getOnlineCount() {
        return onlineCount.get();
    }
 
    public static int addOnlineCount() {
        return onlineCount.incrementAndGet();
    }
 
    public static int subOnlineCount() {
        return onlineCount.decrementAndGet();
    }
 
}

(2)HandShake 攔截器實(shí)現(xiàn)

import java.util.Map;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
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.support.HttpSessionHandshakeInterceptor;
 
public class TestHandShakeInterceptor extends HttpSessionHandshakeInterceptor {
 
    private final Logger LOGGER = LoggerFactory.getLogger(TestHandShakeInterceptor.class);
 
    /*
     * 在WebSocket連接建立之前的操作,以鑒權(quán)為例
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
            WebSocketHandler wsHandler, Map attributes) throws Exception {
 
        LOGGER.info("Handle before webSocket connected. ");
 
        // 獲取url傳遞的參數(shù),通過attributes在Interceptor處理結(jié)束后傳遞給WebSocketHandler
        // WebSocketHandler可以通過WebSocketSession的getAttributes()方法獲取參數(shù)
        ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request;
        String id = serverRequest.getServletRequest().getParameter("id");
        String name = serverRequest.getServletRequest().getParameter("name");
 
        if (tokenValidation.validateSign()) {
            LOGGER.info("Validation passed. WebSocket connecting.... ");
            attributes.put("id", id);
            attributes.put("name", name);
            return super.beforeHandshake(request, response, wsHandler, attributes);
        } else {
            LOGGER.error("Validation failed. WebSocket will not connect. ");
            return false;
        }
    }
 
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
            WebSocketHandler wsHandler, Exception ex) {
        // 省略
    }
 
}

(3)WebSocket 配置類實(shí)現(xiàn)(注冊WebSocket實(shí)現(xiàn)類,綁定接口,同時將實(shí)現(xiàn)類和攔截器綁定)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
 
import TestWebSocketController;
import TestHandShakeInterceptor;
 
@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
 
    @Autowired
    private TestWebSocketController testWebSocketController;
 
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(TestWebSocketController, "/testWebSocket")
                .addInterceptors(new TestHandShakeInterceptor()).setAllowedOrigins("*");
    }
 
}

1.3 補(bǔ)充說明

(1)在WebSocket實(shí)現(xiàn)過程中,尤其是通過“@ServerEndpoint”實(shí)現(xiàn)的時候,可能會出現(xiàn)注入失敗的問題,即注入的Bean為null的問題。可以通過手動注入的方式來解決,需要改造實(shí)現(xiàn)類和SpringBoot啟動類,如下:

@ServerEndpoint("testWebsocket")
@RestController
public class WebSocketController {
 
    private TestService testService;
 
    private static ApplicationContext applicationContext;
 
    @OnOpen
    public void onOpen(Session session) {
        testService = applicationContext.getBean(TestService.class);
    }
 
    @OnClose
    public void onClose() {}
 
    @OnMessage
    public void onMessage(String message, Session session) {}
 
    @OnError
    public void onError(Session session, Throwable error) {}
 
    public static void setApplicationContext(ApplicationContext applicationContext) {
        WebSocketController.applicationContext = applicationContext;
    }
 
}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
 
import WebSocketController;
 
@SpringBootApplication
public class Application {
 
    public static void main(String[] args) {
//        SpringApplication.run(Application.class, args);
        SpringApplication springApplication = new SpringApplication(Application.class);
        ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);
        WebSocketController.setApplicationContext(configurableApplicationContext);  // 解決WebSocket不能注入的問題
    }
 
}

2. 客戶端的實(shí)現(xiàn),我嘗試了html和java WebSocketClient兩種方式

2.1 html實(shí)現(xiàn)




    WebSocket示例
    
    


    
    發(fā)送消息
    
    關(guān)閉WebSocket連接     
    
      var websocket = null;     //判斷當(dāng)前瀏覽器是否支持WebSocket     if ('WebSocket' in window) {         // 不帶參數(shù)的寫法         websocket = new WebSocket("ws://127.0.0.1:18080/testWebsocket");         // 通過路徑傳遞參數(shù)的方法(服務(wù)端采用第一種方法"@ServerEndpoint"實(shí)現(xiàn))         websocket = new WebSocket("ws://127.0.0.1:18080/testWebsocket/23/Lebron");         // 通過類似GET請求方式傳遞參數(shù)的方法(服務(wù)端采用第二種方法"WebSocketHandler"實(shí)現(xiàn))         websocket = new WebSocket("ws://127.0.0.1:18080/testWebsocket?id=23&name=Lebron");     }     else {         alert('當(dāng)前瀏覽器 Not support websocket')     }       //連接發(fā)生錯誤的回調(diào)方法     websocket.onerror = function () {         setMessageInnerHTML("WebSocket連接發(fā)生錯誤");     };       //連接成功建立的回調(diào)方法     websocket.onopen = function () {         setMessageInnerHTML("WebSocket連接成功");     }       //接收到消息的回調(diào)方法     websocket.onmessage = function (event) {         setMessageInnerHTML(event.data);     }       //連接關(guān)閉的回調(diào)方法     websocket.onclose = function () {         setMessageInnerHTML("WebSocket連接關(guān)閉");     }       //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時,主動去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會拋異常。     window.onbeforeunload = function () {         closeWebSocket();     }       //將消息顯示在網(wǎng)頁上     function setMessageInnerHTML(innerHTML) {         document.getElementById('message').innerHTML += innerHTML + '
';     }       //關(guān)閉WebSocket連接     function closeWebSocket() {         websocket.close();     }       //發(fā)送消息     function send() {         var message = document.getElementById('text').value;         websocket.send(message);     }

2.2 Java WebSocketClient實(shí)現(xiàn)

(1)WebSocketClient 實(shí)現(xiàn)類

import java.net.URI;
 
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class TestWebSocketClient extends WebSocketClient {
 
    private final Logger LOGGER = LoggerFactory.getLogger(TestWebSocketClient.class);
 
    public TestWebSocketClient(URI serverUri) {
        super(serverUri);
    }
 
    public TestWebSocketClient(URI serverUri, Draft protocolDraft) {
        super(serverUri, protocolDraft);
    }
 
    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        LOGGER.info("Open a WebSocket connection on client. ");
    }
 
    @Override
    public void onClose(int arg0, String arg1, boolean arg2) {
        LOGGER.info("Close a WebSocket connection on client. ");
    }
 
    @Override
    public void onMessage(String msg) {
        LOGGER.info("WebSocketClient receives a message: " + msg);
    }
 
    @Override
    public void onError(Exception exception) {
        LOGGER.error("WebSocketClient exception. ", exception);
    }
 
}

(2)WebSocketClient 發(fā)送數(shù)據(jù)

String serverUrl = "ws://127.0.0.1:18080/testWebsocket"
URI recognizeUri = new URI(serverUrl);
client = new TestWebSocketClient(recognizeUri, new Draft_6455());
client.connect();
client.send("This is a message from client. ");

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。


網(wǎng)站標(biāo)題:SpringBoot跟WebSocket的開發(fā)過程是怎樣的
新聞來源:http://weahome.cn/article/ihdgig.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部