當前位置:
首頁 > 知識 > SpringBoot | 第十九章:web 應用開發之 WebSocket

SpringBoot | 第十九章:web 應用開發之 WebSocket

(點擊

上方公眾號

,可快速關注)




來源:oKong ,


blog.lqdev.cn/2018/08/14/springboot/chapter-nineteen/




前言



web開發也講解了三章了,這章節開始講解關於與前端通信相關知識。實現一個在線聊天室類似的功能或者後端推送消息到前端,在沒有WebSocket時,讀大學那伙還有接觸過DWR(Direct Web Remoting),也使用過輪詢的方式,當Servlet3.0出來後,也有使用其非同步連接機制進行前後端通信的。今天我們就來說說WebSocket。它是HTML5開始提供的。




關於WebSocket




WebSocket是HTML5開始提供的一種在單個TCP連接上進行全雙工通訊的協議。




在WebSocket API中,瀏覽器和伺服器只需要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。



瀏覽器通過JavaScript向伺服器發出建立WebSocket連接的請求,連接建立以後,客戶端和伺服器端就可以通過TCP連接直接交換數據。




當獲取Web Socket連接後,你可以通過 send() 方法來向伺服器發送數據,並通過 onmessage事件來接收伺服器返回的數據。




對於前端,創建一個WebSocket對象,如下:





var Socket = new WebSocket(url, [protocol] );



說明:第一個參數 url, 指定連接的 URL。第二個參數 protocol 是可選的,指定了可接受的子協議。




WebSocker屬性




以下是WebSocket對象的屬性。假定我們使用了以上代碼創建了Socket對象:






WebSocket事件




以下是 WebSocket 對象的相關事件。假定我們使用了以上代碼創建了 Socket 對象:







WebSocket方法




以下是 WebSocket 對象的相關方法。假定我們使用了以上代碼創建了 Socket 對象:







WebSocket實踐



前面介紹了在瀏覽器端中webSocket的相關知識點,現在我們就來搭建一個後台對接應用,以實現一個簡單的在線聊天室。




一點知識





後端關於WebSocket的實現是基於JSR356標準的。該標準的出現,統一了


WebSocket的代碼寫法。只要支持web容器支持JSR356標準,那麼實現方式是一致的。而目前實現方式有兩種,一種是註解方式,另一種就是繼承繼承javax.websocket.Endpoint類了。



常用註解說明




@WebSocketEndpoint


註解是一個類層次的註解,它的功能主要是將目前的類定義成一個websocket伺服器端。註解的值將被用於監聽用戶連接的終端訪問URL地址。




@onOpen

打開一個新連接,即有新連接時,會調用被此註解的方法。




@onClose


關閉連接時調用。




@onMessage


當伺服器接收到客戶端發送的消息時所調用的方法。




@PathParam


接收uri參數的,與@PathVariable功能差不多,可通過url獲取對應值


搭建一個簡易聊天室




0.加入POM依賴。





<dependency>


    <groupId>org.springframework.boot</groupId>


    <artifactId>spring-boot-starter-web</artifactId>


</dependency>


<dependency>


    <groupId>org.springframework.boot</groupId>


    <artifactId>spring-boot-starter-websocket</artifactId>


</dependency>




1.編寫控制層,對應WebSocket的各事件。同時抽取了個公用類,進行通用方法調用。




WebSocketController.java





/**


 * websocket 簡易聊天


 * @author oKong


 *


 */


//由於是websocket 所以原本是@RestController的http形式 


//直接替換成@ServerEndpoint即可,作用是一樣的 就是指定一個地址


//表示定義一個websocket的Server端


@Component


@ServerEndpoint(value = "/my-chat/{usernick}")


@Slf4j


public class WebSocketController {


     


    /**


     * 連接事件 加入註解


     * @param session


     */


    @OnOpen


    public void onOpen(@PathParam(value = "usernick") String userNick,Session session) {


        String message = "有新遊客[" + userNick + "]加入聊天室!";


        log.info(message);


        WebSocketUtil.addSession(userNick, session);    


        //此時可向所有的在線通知 某某某登錄了聊天室         


        WebSocketUtil.sendMessageForAll(message);


    }


     


    @OnClose


    public void onClose(@PathParam(value = "usernick") String userNick,Session session) {


        String message = "遊客[" + userNick + "]退出聊天室!";


        log.info(message);


        WebSocketUtil.remoteSession(userNick);  


        //此時可向所有的在線通知 某某某登錄了聊天室         


        WebSocketUtil.sendMessageForAll(message);


    }


     


    @OnMessage


    public void OnMessage(@PathParam(value = "usernick") String userNick, String message) {


        //類似群發


        String info = "遊客[" + userNick + "]:" + message;


        log.info(info);


        WebSocketUtil.sendMessageForAll(message);


    } 


     


    @OnError


    public void onError(Session session, Throwable throwable) {


        log.error("異常:", throwable);


        try {


            session.close();


        } catch (IOException e) {


            e.printStackTrace();


        }


        throwable.printStackTrace();


    }


 


}




WebSocketUtil.java





public class WebSocketUtil {


 


    /**


     * 簡單使用map進行存儲在線的session


     * 


     */


    private static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();


     


    public static void addSession(String userNick,Session session) {


        //putIfAbsent 添加鍵—值對的時候,先判斷該鍵值對是否已經存在


        //不存在:新增,並返回null


        //存在:不覆蓋,直接返回已存在的值


//      ONLINE_SESSION.putIfAbsent(userNick, session);


        //簡單示例 不考慮複雜情況。。怎麼簡單怎麼來了。。


        ONLINE_SESSION.put(userNick, session);


    }


     


    public static void remoteSession(String userNick) {


        ONLINE_SESSION.remove(userNick);


    }


     


    /**


     * 向某個用戶發送消息


     * @param session 某一用戶的session對象


     * @param message


     */


    public static void sendMessage(Session session, String message) {


        if(session == null) {


            return;


        }


        // getAsyncRemote()和getBasicRemote()非同步與同步


        Async async = session.getAsyncRemote();


        //發送消息


        async.sendText(message);


    }


     


    /**


     * 向所有在線人發送消息


     * @param message


     */


    public static void sendMessageForAll(String message) {


        //jdk8 新方法


        ONLINE_SESSION.forEach((sessionId, session) -> sendMessage(session, message));


    }


}




注意點:






  • @ServerEndpoint的value值填寫時,開頭需要加上/,不然會提示路徑無效。



  • 需要加上類型@Component註解,使得能被掃描到。



  • 這裡的session等,都在包javax.websocket包下的,注意區分。




2.編寫主啟動類,主要是加入註解@EnableWebSocket和申明一個Websocket endpoint類。





@SpringBootApplication


@EnableWebSocket


@Slf4j


public class Chapter19Application {


 


    public static void main(String[] args) {


        SpringApplication.run(Chapter19Application.class, args);


        log.info("Chapter19啟動!");


    }


     


    /**


     * 會自動註冊使用了@ServerEndpoint註解聲明的Websocket endpoint


     * 要注意,如果使用獨立的servlet容器,


     * 而不是直接使用springboot的內置容器,


     * 就不要注入ServerEndpointExporter,因為它將由容器自己提供和管理。


     */


    @Bean


    public ServerEndpointExporter serverEndpointExporter() {


        return new ServerEndpointExporter();


    }


}




3.啟動應用,利用在線的測試工具進行測試。這裡直接使用了http://coolaf.com/tool/chattest進行測試。當然也可以自己寫一個html了。




首先,輸入我們的服務地址:ws://127.0.0.1:8080/my-chat/okong,連接後就可以看見伺服器返回的消息了。







我們再開一個標籤頁,然後繼續以另一個身份進入:







這時,可以看見第一個頁面開的,也收到消息了。現在我們發送一條消息:







然後,其中一個斷開連接:







然後可以愉快聊天了,簡單的一個聊天室就完成了。




參考資料






  1. https://docs.spring.io/spring/docs/4.3.18.RELEASE/spring-framework-reference/htmlsingle/#websocket



  2. https://docs.spring.io/spring-boot/docs/1.5.15.RELEASE/reference/htmlsingle/#boot-features-websockets



  3. http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html



  4. http://www.runoob.com/html/html5-websocket.html




總結




本章節主要是講解了WebSocket的使用。因為有統一標準的存在,編寫webSocket也是很簡單的。對於如何一對一聊天,大家可以自行編寫下,因為知道了對方名稱,就能找出對方的session然後就能發送消息了。




最後




目前互聯網上很多大佬都有SpringBoot系列教程,如有雷同,請多多包涵了。本文是作者在電腦前一字一句敲的,每一步都是自己實踐的。若文中有所錯誤之處,還望提出,謝謝。




系列






  • SpringBoot | 第一章:第一個 SpringBoot 應用



  • SpringBoot | 第二章:lombok 介紹及簡單使用



  • SpringBoot | 第三章:springboot 配置詳解



  • SpringBoot | 第四章:日誌管理



  • SpringBoot | 第五章:多環境配置



  • SpringBoot | 第六章:常用註解介紹及簡單使用



  • SpringBoot | 第七章:過濾器、監聽器、攔截器



  • SpringBoot | 第八章:統一異常、數據校驗處理



  • SpringBoot | 第九章:Mybatis-plus 的集成和使用



  • SpringBoot | 第十章:Swagger 2 的集成和使用



  • SpringBoot | 第十一章:Redis 的集成和簡單使用



  • SpringBoot | 第十二章:RabbitMQ 的集成和使用



  • SpringBoot | 第十三章:測試相關 ( 單元測試、性能測試 )



  • SpringBoot | 第十四章:基於 Docker 的簡單部署



  • SpringBoot | 第十五章:基於 Postman 的 RESTful 介面測試



  • SpringBoot | 第十六章:web 應用開發



  • SpringBoot | 第十七章:web 應用開發之文件上傳



  • SpringBoot | 第十八章:web 應用開發之WebJars 使用




【關於投稿】




如果大家有原創好文投稿,請直接給公號發送留言。




① 留言格式:


【投稿】+《 文章標題》+ 文章鏈接

② 示例:


【投稿】《不要自稱是程序員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/

③ 最後請附上您的個人簡介哈~






看完本文有收穫?請轉發分享給更多人


關注「ImportNew」,提升Java技能


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 ImportNew 的精彩文章:

塵埃落定,JDK 11 確定將引入 Shebang #! 符號
SpringBoot | 第十三章:測試相關 ( 單元測試、性能測試 )

TAG:ImportNew |