標籤:websocket java tomcat
1、前言
一直沒有怎麼做過前端的東西,但是最近的項目中,前端人員奇缺,公司又不安排新的人員進入,所以我這個後台開發人員只能拉過來坐前端了,前段的東西感覺一大堆,CSS,js自不必說,HTML生態圈就有很多的技術要去學習,好吧,那就一個一個的學習整理啦,先來說說最近這個項目的前端用到什麼技術吧。
1、Restful:DropWizard這個很簡單,兩Apsara Infrastructure Management Framework本上就能拿下
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.4IDE: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的使用的。
WebSocket Java Programming入門-1(annotated)