HTML5給Web瀏覽器帶來了全雙工TCP連接websocket標准服務器的能力。
換句話說,瀏覽器能夠與服務器建立連接,通過已建立的通信信道來發送和接收數據而不需要由HTTP協議引入額外其他的開銷來實現。
在本教程中我們將在Java EE環境下實現一個簡單的websockect服務器端來和客戶端進行數據交互。
本教程需要以下環境:
- JDK 1.7.0.21
- tomcat 7
WebSocket服務器端
WebSocketServer 代碼:
package com.bing.biz.websocket; import java.io.IOException; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; //該注解用來指定一個URI,客戶端可以通過這個URI來連接到WebSocket。類似Servlet的注解mapping。無需在web.xml中配置。 @ServerEndpoint("/webSocketServer/{userId}") public class WebSocketServer { /** * 連接建立成功調用的方法 * @param session 可選的參數。session為與某個客戶端的連接會話,需要通過它來給客戶端發送數據 * @throws IOException */ @OnOpen public void onOpen(@PathParam("userId") String userId,Session session) throws IOException{ /* if(userId!=null){ if(!SocketUtils.hasConnection(userId)){ SocketUtils.put(userId,session); } else{ //相同用戶只允許在一個地方登錄(網頁版內部判斷)。 SocketUtils.sendMessage(userId,"forcelogout","該用戶已在其他地方登錄,此次登錄將被強制退出。",0,""); SocketUtils.remove(userId,session.getId()); SocketUtils.put(userId,session); } }*/ System.out.println("Client connected "+userId); } /** * 連接關閉調用的方法 */ @OnClose public void onClose(@PathParam("userId") String userId,Session session)throws IOException{ //SocketUtils.remove(userId,session.getId()); System.out.println("Connection closed"); } /** * 收到客戶端消息后調用的方法 * @param message 客戶端發送過來的消息 * @param session 可選的參數 * @throws IOException */ @OnMessage public void onMessage(@PathParam("userId") String userId,String message, Session session) throws IOException { // Print the client message for testing purposes System.out.println("Received: " + message); // Send the first message to the client session.getBasicRemote().sendText("This is the first server message"); // Send 3 messages to the client every 5 seconds int sentMessages = 0; while(sentMessages < 3){ session.getBasicRemote(). sendText("This is an intermediate server message. Count: " + sentMessages); sentMessages++; } // Send a final message to the client session.getBasicRemote().sendText("This is the last server message"); } /** * 發生錯誤時調用 * @param session * @param error */ @OnError public void onError(Session session, Throwable error){ error.printStackTrace(); } }
你可能已經注意到我們從 javax.websocket包中引入了一些類。
@ServerEndpoint 注解是一個類層次的注解,它的功能主要是將目前的類定義成一個websocket服務器端。注解的值將被用於監聽用戶連接的終端訪問URL地址。
onOpen 和 onClose 方法分別被@OnOpen和@OnClose 所注解。這兩個注解的作用不言自明:他們定義了當一個新用戶連接和斷開的時候所調用的方法。
onMessage 方法被@OnMessage所注解。這個注解定義了當服務器接收到客戶端發送的消息時所調用的方法。注意:這個方法可能包含一個javax.websocket.Session可選參數(在我們的例子里就是session參數)。如果有這個參數,容器將會把當前發送消息客戶端的連接Session注入進去。
本例中我們僅僅是將客戶端消息內容打印出來,然后首先我們將發送一條開始消息,之后間隔5秒向客戶端發送1條測試消息,共發送3次,最后向客戶端發送最后一條結束消息。
WebSocket客戶端
index.jsp代碼:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE html> <html> <head> <title>Testing websockets</title> </head> <body> <div> <input type="submit" value="Start" onclick="start()" /> </div> <div id="messages"></div> <script type="text/javascript"> //建立websocket連接 var websocket = new WebSocket('ws://localhost:8080/bing/webSocketServer/bing'); websocket.onopen = function (evnt) { document.getElementById('messages').innerHTML = 'Connection established'; }; websocket.onmessage = function (evnt) { document.getElementById('messages').innerHTML += '<br />' + event.data; }; websocket.onerror = function (evnt) { }; websocket.onclose = function (evnt) { }; function start() { websocket.send('hello'); return false; } </script> </body> </html>
這是一個簡單的頁面,包含有JavaScript代碼,這些代碼創建了一個websocket連接到websocket服務器端。
onOpen 我們創建一個連接到服務器的連接時將會調用此方法。
onError 當客戶端-服務器通信發生錯誤時將會調用此方法。
onMessage 當從服務器接收到一個消息時將會調用此方法。在我們的例子中,我們只是將從服務器獲得的消息添加到DOM。
我們連接到websocket 服務器端,使用構造函數 new WebSocket() 而且傳之以端點URL:
ws://localhost:8080/bing/webSocketServer/bing ---bing 后台的userid
測試
現在我們可以訪問測試頁面對我們的應用進行測試:
http://localhost:8080/bing/index.jsp


后台:

