1. 程式人生 > >WebSocket Java Programming入門-1(annotated)

WebSocket Java Programming入門-1(annotated)

1、前言

一直沒有怎麼做過前端的東西,但是最近的專案中,前端人員奇缺,公司又不安排新的人員進入,所以我這個後臺開發人員只能拉過來坐前端了,前段的東西感覺一大堆,CSS,js自不必說,HTML生態圈就有很多的技術要去學習,好吧,那就一個一個的學習整理啦,先來說說最近這個專案的前端用到什麼技術吧。

1、Restful:DropWizard這個很簡單,兩天基本上就能拿下

2、Js Framework :AngularJS 這個JS庫的確很酷,最近學習的過程中越來越喜歡這個東西了,打算以後再整理一些AngularJS的學習筆記和過程

3、前端和後端的通訊的方式不是那種request和response的方式,而是採用HTML5的WebSocket。

4、其他技術我就不一一列舉了

在學習websocket的過程中我閱讀了一下tomcat的websocket examples當然最重要的是閱讀了一本比較不錯的系統化的WEBSOCKET書,推薦給大家《JAVA WEBSOCKET PROGRAMMING》然後我盡力將自己學到的東西,儘可能通俗的詳細地介紹一下,方便和大家交流。

2、環境配置

     網上關於Websocket是什麼的文章多如牛毛,我這裡也就不用挨個去摘抄,先直接來一個比較直觀的例子,本文中採用的是基於註解的方式,來演示一個Echo Server的例項

2.1、執行環境要求:

Tomcat版本必須在7.0.47版本以上才可以
      JDK必須在1.7版本以上才可以

2.2、開發環境:(不做強制要求,根據個人的愛好,我只是列舉一下我的開發環境)

Maven:3.0.4 IDE:Intellij IDEA

3、第一個基於註解的WebSocket Demo


好了,一切準備就緒,我們來看看下面的程式碼吧,然後我再一一說明其中的一些細節

3.1、 Maven的POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <parent>
        <artifactId>websocket</artifactId>
        <groupId>websocket</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>websocket-anotation</artifactId>
    <packaging>war</packaging>
    <name>websocket-anotation Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-api</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>websocket-anotation</finalName>
    </build>
</project>
其中我們引入了javax websocket的標準api介面,並且將其的scope設定成provided(tomcat容器已經自帶了這個包,我們不需要重複釋出,指定為provided的目的就是為了在編寫程式碼的過程中使用而已)。

3.2、服務段程式碼:

package com.wangwenjun.websocket.annotation;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/hello")
public class HelloWorldServer {

    @OnMessage
    public String sayHello(String incomingMessage) {
        return "I got this(" + incomingMessage + ") so I am sending it back to you!";
    }

    @OnOpen
    public void open(Session session) {
        System.out.println("On Open---" + session.getBasicRemote());
    }

    @OnClose
    public void close() {
        System.out.println("Close.");
    }
}
其實這個例子中只要有一個方法被@OnMessage註解即可,其他的open和close 暫時可以忽略掉,Websocket的方式不僅可以和服務段傳遞文字資訊也可以互動二進位制的形式(InputStream),不僅可以返回字串,也可以返回二進位制流(OutputStream),而且還可以得到整個回話的引用如Session,也就意味著我們下面的方法都是合理的
@OnMessage
    public void test1(String test){
        //do nothing.
    }

    @OnMessage
    public void test2(InputStream inputStream){
        //do nothing.
    }

    @OnMessage
    public OutputStream test3(InputStream inputStream){
        //do nothing.
        return null;
    }

    @OnMessage
    public void test4(String text,Session session){
        //do nothing.
    }
等等諸如此類吧,都是可行的,好了我們說會剛才那個方法sayHello,該方法接受一個文字字串,並且返回一個文字字串,註解為OnMessage,表示它接受來自客戶端的資訊並且處理之。 3.3、客戶端程式碼
<!DOCTYPE HTML>

<html>
<head>
    <title>WebSocket Learning Example(Hello World)</title>
    <script type="text/javascript">
        var ws;
        function init() {
            outputArea = document.getElementById("output");
        }

        function sayHello() {
            var url = "ws://localhost:8080/websocket-anotation/hello";
            writeMessageToScreen("Connecting to " + url);
            ws = new WebSocket(url);
            ws.onopen = function (event) {
                writeMessageToScreen("Connected.");
                var message=document.getElementById("message").value;
                doSend(message);
            }

            ws.onmessage = function (event) {
                writeMessageToScreen("Received message: " + event.data);
                ws.close();
            }

            ws.onerror = function (event) {
                writeMessageToScreen("Occur Error:<span style='color:red'>" + event.data + "</span>");
                ws.close();
            }
        }

        function doSend(message) {
            ws.send(message);
            writeMessageToScreen("Sent message: " + message);
        }

        function writeMessageToScreen(message) {
            var p = document.createElement("p");
            p.style.wordWrap = "break-word";
            p.innerHTML = message;
            outputArea.appendChild(p);
        }

        this.addEventListener("load", init, false);
    </script>
</head>
<body>
<h1>Hello World Server</h1>

<div style="text-align:left">
    <form action="#">
        <input type="text"  id="message" placeholder="Please enter your name."/>
        <input type="button" id="sender" value="PressMeToSend" onclick="sayHello()"/>
    </form>
</div>
<div id="output">
</div>
</body>
</html>

客戶端的程式碼關於DOM的操作我用的是最元生的處理方式,並沒有採用Jquery等對Dom支援特別好的第三方庫,想必大家都能看得明白,我就不做更多的解釋了,關鍵來說說WebSocket物件,websocket物件在JS宿主(瀏覽器)中並不是都被支援,IE就從第十個版本才開始支援的,如果你做的是一個網際網路應用,沒有辦法強制讓客戶試用統一支援websocket物件的瀏覽器,你最好能夠判斷一下js環境是否支援websocket的物件,判斷的方法也是非常簡單,如下的幾種方式都可以
//method 1
        if(window.WebSocket){

        }

        //method 2
        if("WebSocket" in window)
        {

        }
        
        //method 3
        if(window["WebSocket"]){
            
        }
好了,我們來說一下上面JS程式碼中的幾個關鍵部分吧
 var url = "ws://localhost:8080/websocket-anotation/hello";
定義了Websocket ServerEndpoint的地址,記住協議是WS哦,不要像我一樣第一次學習的習慣性的用http,最後的那個URI/hello是我們在我們的HelloWorldServer中用@ServerEnmdpoint註解的Value值,應該不難理解吧。
ws = new WebSocket(url);
建立一個WebSocket的物件,如果能夠建立成功就可以使用我們的WebSocket了,不過更加嚴謹的做法應該是像我在前面所說的那樣應該判斷JS宿主環境是否支援WebSocket,否則下面的程式碼都會出現錯誤的。 WebSocket最美的地方有很多回調函式在裡面,當發生相關的事情會被自動呼叫,如下面的程式碼就是註冊相關的回撥函式
ws.onopen = function (event) {
                writeMessageToScreen("Connected.");
                var message=document.getElementById("message").value;
                doSend(message);
            }

            ws.onmessage = function (event) {
                writeMessageToScreen("Received message: " + event.data);
                ws.close();
            }

            ws.onerror = function (event) {
                writeMessageToScreen("Occur Error:<span style='color:red'>" + event.data + "</span>");
                ws.close();
            }

第一個當成功連線之後會被呼叫,第二個是收到了來自ServerEndpoint的訊息之後的回撥,第三個是發生了錯誤會被回撥,怎麼樣很爽吧。 最後一個比較關鍵的方法就是傳送訊息到服務端,但是不得不承認真的很簡單,簡單到就一行
ws.send(message);

4、釋出

就這麼簡單,寥寥幾行程式碼就可以實現一個最基本的客戶端與服務端通訊的小程式,寫到這裡我們應該釋出一下,看看運新多個效果如何,執行 mvn clean package命令,將web專案打包成一個war包 ,然後拷貝到你的tomcat webapps目錄下面,當然你也可以安裝tomcat自動部署外掛,執行命令即可自動將war包釋出到webapps下面去,感興趣的可以自己嘗試,我在這裡就不做演示了,然後訪問頁面:http://localhost:8080/websocket-anotation/ 自己玩一把吧。

5、簡單總結

Http是一個非持續連線協議,也就是說每一次的和伺服器互動都是一個新的連線,我們可以理解為一個基於TCP的短連線協議,但是Websocket的出現,給Web開發人員多了一個長連線的選擇,我們可以和服務端始終保持回話,並且接受來自服務端的資訊,在網際網路中,基於Websocket的應用越來越多了,學習掌握是很有必要的,在接下來還會繼續進行更新,再說一遍《JAVA WEBSOCKET PROGRAMMING》這本書真的很好,而且只有兩百多頁,看完之後加以練習,相信你會精通WebSocket的使用的。