實(shí)現(xiàn)web端的推送目前有幾種方式:
* 輪詢
客戶端定時(shí)向服務(wù)器發(fā)送ajax請(qǐng)求,服務(wù)器接到請(qǐng)求后馬上返回響應(yīng)信息并關(guān)閉連接瘟判。
優(yōu)點(diǎn):后端程序編寫簡(jiǎn)單
缺點(diǎn):請(qǐng)求中有大多是無用的怨绣,浪費(fèi)帶寬和服務(wù)器資源。
示例:適用于小型應(yīng)用
* websocket
WebSocket是HTML5開始提供的一種瀏覽器與服務(wù)器間進(jìn)行全雙工通訊的網(wǎng)絡(luò)技術(shù)拷获。依靠這種技術(shù)可以實(shí)現(xiàn)客戶端和服務(wù)器端的長(zhǎng)連接篮撑,雙向?qū)崟r(shí)通信。在 WebSocket API 中匆瓜,瀏覽器和服務(wù)器只需要完成一次握手赢笨,兩者之間就直接可以創(chuàng)建持久性的連接未蝌,并進(jìn)行雙向數(shù)據(jù)傳輸。
優(yōu)點(diǎn):節(jié)省服務(wù)器資源和帶寬质欲,實(shí)時(shí)進(jìn)行通信
缺點(diǎn):少部分瀏覽器不支持树埠,且不同瀏覽器支持的程度和方式有區(qū)別
那么接下來說明一下自己寫的一個(gè)超簡(jiǎn)單的demo,關(guān)于接收消息的一些邏輯控制未寫入代碼嘶伟,此處只做簡(jiǎn)單的推送功能展示怎憋。
1、服務(wù)端
* 引入jar包:
敲重點(diǎn):注意scope作用域九昧, provided--在編譯和測(cè)試的過程有效绊袋,最后生成war包時(shí)不會(huì)加入
<!-- 引入websocket -->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
* 消息處理類(注意前后端websocket對(duì)象是同一個(gè))
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
@ServerEndpoint("/websocket/endpoint")
public class WebsocketHandler {
private static Map<String, WebsocketHandler> clients = new ConcurrentHashMap<String, WebsocketHandler>();
@OnOpen
public void onOpen(Session session) throws IOException {
//如果有用戶信息,可以將用戶編碼之類的唯一標(biāo)識(shí)作為clients的key铸鹰,這樣可以保證一個(gè)用戶只有一個(gè)websocket client有效(此處的“1”僅僅作為demo的測(cè)試?yán)樱?
//如果同一個(gè)用戶可以擁有多個(gè)websocket client癌别,可以將session.getId()作為key,根據(jù)實(shí)際業(yè)務(wù)需求來設(shè)置即可
clients.put("1", this);
System.out.println("已連接");
}
@OnMessage
public void onMessage(String message) {
//以下代碼省略...
System.out.println(message);
for (WebsocketHandler client : clients.values()) {
client.session.getBasicRemote().sendText(message);
}
}
@OnError
public void onError(Throwable t) {
//以下代碼省略...
t.printStackTrace();
}
@OnClose
public void onClose(Session session, CloseReason reason) {
//以下代碼省略...
System.out.println(String.format("Session %s closed because of %s", session.getId(), reason));
System.out.println("已關(guān)閉連接");
}
public static void pushMsg(String message){
// “1”只是測(cè)試用的key
WebsocketHandler client = clients.get("1");
try {
if(client != null){
client.session.getBasicRemote().sendText(message);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
* 后端對(duì)外消息推送接口
@ResponseBody
@RequestMapping(value="/sendMessage", method = RequestMethod.GET)
public void sendMessage() throws IOException {
WebsocketHandler.pushMsg("這是我需要發(fā)送的消息蹋笼,記得給我傳達(dá)展姐,后面可以做成通用的接口");
}
2、客戶端
<!-- html -->
<button onclick="sendMessage()">發(fā)送消息</button>
<button onclick="closeWebSocket()">關(guān)閉</button>
<div>這是顯示結(jié)果的地方:
<p id="message" style="color:red;"></p>
</div>
<!-- javascript -->
<script type="text/javascript" src="../js/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
var websocket = null;
var url = "ws://localhost:8081/websocket-demo/websocket/endpoint";
$(document).ready(function(){
//判斷當(dāng)前瀏覽器是否支持WebSocket
if ('WebSocket' in window) {
alert("瀏覽器支持Websocket")
websocket = new WebSocket(url);
} else {
alert('當(dāng)前瀏覽器 Not support websocket');
}
if(websocket != null){
//連接發(fā)生錯(cuò)誤的回調(diào)方法
websocket.onerror = function() {
alert("WebSocket連接發(fā)生錯(cuò)誤")
setMessageInnerHTML("WebSocket連接發(fā)生錯(cuò)誤");
};
//連接成功建立的回調(diào)方法
websocket.onopen = function() {
alert("WebSocket連接成功")
setMessageInnerHTML("WebSocket連接成功");
}
//接收到消息的回調(diào)方法
websocket.onmessage = function(event) {
alert("接收到消息的回調(diào)方法")
alert("這是后臺(tái)推送的消息:"+event.data);
// websocket.close();
// alert("webSocket已關(guān)閉剖毯!")
}
//連接關(guān)閉的回調(diào)方法
websocket.onclose = function() {
setMessageInnerHTML("WebSocket連接關(guān)閉");
}
}
});
//監(jiān)聽窗口關(guān)閉事件圾笨,當(dāng)窗口關(guān)閉時(shí),主動(dòng)去關(guān)閉websocket連接逊谋,防止連接還沒斷開就關(guān)閉窗口擂达,server端會(huì)拋異常。
window.onbeforeunload = function() {
closeWebSocket();
}
//關(guān)閉WebSocket連接
function closeWebSocket() {
websocket.close();
}
//將消息顯示在網(wǎng)頁上
function setMessageInnerHTML(innerHTML) {
$("#message").text(innerHTML);
}
</script>