中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

SpringBoot | 第十九章:web 應(yīng)用開(kāi)發(fā)之 WebSocket

2018-09-17    來(lái)源:importnew

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

前言

web開(kāi)發(fā)也講解了三章了,這章節(jié)開(kāi)始講解關(guān)于與前端通信相關(guān)知識(shí)。實(shí)現(xiàn)一個(gè)在線聊天室類(lèi)似的功能或者后端推送消息到前端,在沒(méi)有WebSocket時(shí),讀大學(xué)那伙還有接觸過(guò)DWR(Direct Web Remoting),也使用過(guò)輪詢(xún)的方式,當(dāng)Servlet3.0出來(lái)后,也有使用其異步連接機(jī)制進(jìn)行前后端通信的。今天我們就來(lái)說(shuō)說(shuō)WebSocket。它是HTML5開(kāi)始提供的。

關(guān)于WebSocket

WebSocketHTML5開(kāi)始提供的一種在單個(gè)TCP連接上進(jìn)行全雙工通訊的協(xié)議。

WebSocket API中,瀏覽器和服務(wù)器只需要做一個(gè)握手的動(dòng)作,然后,瀏覽器和服務(wù)器之間就形成了一條快速通道。兩者之間就直接可以數(shù)據(jù)互相傳送。

瀏覽器通過(guò)JavaScript向服務(wù)器發(fā)出建立WebSocket連接的請(qǐng)求,連接建立以后,客戶(hù)端和服務(wù)器端就可以通過(guò)TCP連接直接交換數(shù)據(jù)。

當(dāng)獲取Web Socket連接后,你可以通過(guò)?send()?方法來(lái)向服務(wù)器發(fā)送數(shù)據(jù),并通過(guò)?onmessage事件來(lái)接收服務(wù)器返回的數(shù)據(jù)。

對(duì)于前端,創(chuàng)建一個(gè)WebSocket對(duì)象,如下:

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

說(shuō)明:第一個(gè)參數(shù) url, 指定連接的 URL。第二個(gè)參數(shù) protocol 是可選的,指定了可接受的子協(xié)議。

WebSocker屬性

以下是WebSocket對(duì)象的屬性。假定我們使用了以上代碼創(chuàng)建了Socket對(duì)象:

屬性 描述
Socket.readyState 只讀屬性?readyState?表示連接狀態(tài),可以是以下值:
0 – 表示連接尚未建立。
1 – 表示連接已建立,可以進(jìn)行通信。
2 – 表示連接正在進(jìn)行關(guān)閉。
3 – 表示連接已經(jīng)關(guān)閉或者連接不能打開(kāi)。
Socket.bufferedAmount 只讀屬性?bufferedAmount?已被 send() 放入正在隊(duì)列中等待傳輸,但是還沒(méi)有發(fā)出的 UTF-8 文本字節(jié)數(shù)。

WebSocket事件

以下是 WebSocket 對(duì)象的相關(guān)事件。假定我們使用了以上代碼創(chuàng)建了 Socket 對(duì)象:

事件 事件處理程序 描述
open Socket.onopen 連接建立時(shí)觸發(fā)
message Socket.onmessage 客戶(hù)端接收服務(wù)端數(shù)據(jù)時(shí)觸發(fā)
error Socket.onerror 通信發(fā)生錯(cuò)誤時(shí)觸發(fā)
close Socket.onclose 連接關(guān)閉時(shí)觸發(fā)

WebSocket方法

以下是 WebSocket 對(duì)象的相關(guān)方法。假定我們使用了以上代碼創(chuàng)建了 Socket 對(duì)象:

方法 描述
Socket.send() 使用連接發(fā)送數(shù)據(jù)
Socket.close() 關(guān)閉連接

WebSocket實(shí)踐

前面介紹了在瀏覽器端webSocket的相關(guān)知識(shí)點(diǎn),現(xiàn)在我們就來(lái)搭建一個(gè)后臺(tái)對(duì)接應(yīng)用,以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的在線聊天室。

一點(diǎn)知識(shí)

后端關(guān)于WebSocket的實(shí)現(xiàn)是基于JSR356標(biāo)準(zhǔn)的。該標(biāo)準(zhǔn)的出現(xiàn),統(tǒng)一了
WebSocket的代碼寫(xiě)法。只要支持web容器支持JSR356標(biāo)準(zhǔn),那么實(shí)現(xiàn)方式是一致的。而目前實(shí)現(xiàn)方式有兩種,一種是注解方式,另一種就是繼承繼承javax.websocket.Endpoint類(lèi)了。

常用注解說(shuō)明

  • @WebSocketEndpoint
    注解是一個(gè)類(lèi)層次的注解,它的功能主要是將目前的類(lèi)定義成一個(gè)websocket服務(wù)器端。注解的值將被用于監(jiān)聽(tīng)用戶(hù)連接的終端訪問(wèn)URL地址。
  • @onOpen
    打開(kāi)一個(gè)新連接,即有新連接時(shí),會(huì)調(diào)用被此注解的方法。
  • @onClose
    關(guān)閉連接時(shí)調(diào)用。
  • @onMessage
    當(dāng)服務(wù)器接收到客戶(hù)端發(fā)送的消息時(shí)所調(diào)用的方法。
  • @PathParam
    接收uri參數(shù)的,與@PathVariable功能差不多,可通過(guò)url獲取對(duì)應(yīng)值

搭建一個(gè)簡(jiǎn)易聊天室

0.加入POM依賴(lài)。

<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.編寫(xiě)控制層,對(duì)應(yīng)WebSocket的各事件。同時(shí)抽取了個(gè)公用類(lèi),進(jìn)行通用方法調(diào)用。

WebSocketController.java

/**
 * websocket 簡(jiǎn)易聊天
 * @author oKong
 *
 */
//由于是websocket 所以原本是@RestController的http形式 
//直接替換成@ServerEndpoint即可,作用是一樣的 就是指定一個(gè)地址
//表示定義一個(gè)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);	
		//此時(shí)可向所有的在線通知 某某某登錄了聊天室			
		WebSocketUtil.sendMessageForAll(message);
	}
	
	@OnClose
	public void onClose(@PathParam(value = "usernick") String userNick,Session session) {
		String message = "游客[" + userNick + "]退出聊天室!";
		log.info(message);
		WebSocketUtil.remoteSession(userNick);	
		//此時(shí)可向所有的在線通知 某某某登錄了聊天室			
		WebSocketUtil.sendMessageForAll(message);
	}
	
	@OnMessage
	public void OnMessage(@PathParam(value = "usernick") String userNick, String message) {
		//類(lèi)似群發(fā)
		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 {

	/**
	 * 簡(jiǎn)單使用map進(jìn)行存儲(chǔ)在線的session
	 * 
	 */
    private static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();
    
    public static void addSession(String userNick,Session session) {
    	//putIfAbsent 添加鍵—值對(duì)的時(shí)候,先判斷該鍵值對(duì)是否已經(jīng)存在
    	//不存在:新增,并返回null
    	//存在:不覆蓋,直接返回已存在的值
//    	ONLINE_SESSION.putIfAbsent(userNick, session);
    	//簡(jiǎn)單示例 不考慮復(fù)雜情況。。怎么簡(jiǎn)單怎么來(lái)了。。
    	ONLINE_SESSION.put(userNick, session);
    }
    
    public static void remoteSession(String userNick) {
    	ONLINE_SESSION.remove(userNick);
    }
    
    /**
     * 向某個(gè)用戶(hù)發(fā)送消息
     * @param session 某一用戶(hù)的session對(duì)象
     * @param message
     */
    public static void sendMessage(Session session, String message) {
    	if(session == null) {
    		return;
    	}
    	// getAsyncRemote()和getBasicRemote()異步與同步
    	Async async = session.getAsyncRemote();
    	//發(fā)送消息
    	async.sendText(message);
    }
    
    /**
     * 向所有在線人發(fā)送消息
     * @param message
     */
    public static void sendMessageForAll(String message) {
    	//jdk8 新方法
    	ONLINE_SESSION.forEach((sessionId, session) -> sendMessage(session, message));
    }
}

注意點(diǎn):

  • @ServerEndpoint的value值填寫(xiě)時(shí),開(kāi)頭需要加上/,不然會(huì)提示路徑無(wú)效。
  • 需要加上類(lèi)型@Component注解,使得能被掃描到。
  • 這里的session等,都在包javax.websocket包下的,注意區(qū)分。

2.編寫(xiě)主啟動(dòng)類(lèi),主要是加入注解@EnableWebSocket和申明一個(gè)Websocket endpoint類(lèi)。

@SpringBootApplication
@EnableWebSocket
@Slf4j
public class Chapter19Application {

	public static void main(String[] args) {
		SpringApplication.run(Chapter19Application.class, args);
		log.info("Chapter19啟動(dòng)!");
	}
	
	/**
	 * 會(huì)自動(dòng)注冊(cè)使用了@ServerEndpoint注解聲明的Websocket endpoint
	 * 要注意,如果使用獨(dú)立的servlet容器,
	 * 而不是直接使用springboot的內(nèi)置容器,
	 * 就不要注入ServerEndpointExporter,因?yàn)樗鼘⒂扇萜髯约禾峁┖凸芾怼?	 */
	@Bean
	public ServerEndpointExporter serverEndpointExporter() {
		return new ServerEndpointExporter();
	}
}

3.啟動(dòng)應(yīng)用,利用在線的測(cè)試工具進(jìn)行測(cè)試。這里直接使用了http://coolaf.com/tool/chattest進(jìn)行測(cè)試。當(dāng)然也可以自己寫(xiě)一個(gè)html了。

首先,輸入我們的服務(wù)地址:ws://127.0.0.1:8080/my-chat/okong,連接后就可以看見(jiàn)服務(wù)器返回的消息了。

加入加入

我們?cè)匍_(kāi)一個(gè)標(biāo)簽頁(yè),然后繼續(xù)以另一個(gè)身份進(jìn)入:

新游客加入新游客加入

這時(shí),可以看見(jiàn)第一個(gè)頁(yè)面開(kāi)的,也收到消息了,F(xiàn)在我們發(fā)送一條消息:

發(fā)送消息發(fā)送消息

然后,其中一個(gè)斷開(kāi)連接:

斷開(kāi)連接

斷開(kāi)連接

然后可以愉快聊天了,簡(jiǎn)單的一個(gè)聊天室就完成了。

參考資料

  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

總結(jié)

本章節(jié)主要是講解了WebSocket的使用。因?yàn)橛薪y(tǒng)一標(biāo)準(zhǔn)的存在,編寫(xiě)webSocket也是很簡(jiǎn)單的。對(duì)于如何一對(duì)一聊天,大家可以自行編寫(xiě)下,因?yàn)橹懒藢?duì)方名稱(chēng),就能找出對(duì)方的session然后就能發(fā)送消息了。

最后

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

  • 個(gè)人博客:http://blog.lqdev.cn
  • 完整示例:https://github.com/xie19900123/spring-boot-learning/tree/master/chapter-19

標(biāo)簽: 代碼 服務(wù)器 服務(wù)器端 互聯(lián)網(wǎng) 通信

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:SpringBoot | 第二十章:異步開(kāi)發(fā)之異步請(qǐng)求

下一篇:如果非得了解下 git 系統(tǒng)… – 實(shí)踐篇