java websocket學習
引言:
websocket,webservice傻傻分不清楚,都覺得是很高深的東西,理解中的webservice是一種協議,通訊協議,類似http協議的那種,比如使用webservice協議調後臺介面,而websocket呢?與socket掛鉤?長連線?對未知的東西總是恐懼的,所以默默不敢說話
啟航:
學習過程中突然接觸到了websocket的簡單講解,哦,websocket也是一種協議,它類似ajax,但連線不中斷,接到訊息就響應。叫什麼雙端通訊。websocket請求頭是ws://或者wss://開頭,非安全與安全,後面就和http請求類似。後臺寫法當然與預設的http servlet有些不同,但變化不大,與springMVC的requestMapping有些相似,接受到請求可以進行攔截等處理,當然也可以限制接收請求的具體引數。
概念來一波:
原先實現模擬雙端通訊的手段:
在WebSocket規範提出之前,開發人員若要實現這些實時性較強的功能,經常會使用折衷的解決方法:輪詢(polling)和Comet技術。其實後者本質上也是一種輪詢,只不過有所改進。
輪詢是最原始的實現實時Web應用的解決方案。輪詢技術要求客戶端以設定的時間間隔週期性地向服務端傳送請求,頻繁地查詢是否有新的資料改動。明顯地,這種方法會導致過多不必要的請求,浪費流量和伺服器資源。
Comet技術又可以分為長輪詢和流技術。長輪詢改進了上述的輪詢技術,減小了無用的請求。它會為某些資料設定過期時間,當資料過期後才會向服務端傳送請求;這種機制適合資料的改動不是特別頻繁的情況。流技術
這兩種技術都是基於請求-應答模式,都不算是真正意義上的實時技術;它們的每一次請求、應答,都浪費了一定流量在相同的頭部資訊上,並且開發複雜度也較大。
特點:
1、雙端通訊
2、建立在TCP之上
3、協議識別符號是ws
(如果加密,則為wss
),伺服器網址就是 URL。
接入:
注意:JavaEE 7中出了JSR-356:Java API for WebSocket規範。不少Web容器,如Tomcat,Nginx,Jetty等都支援WebSocket。Tomcat從7.0.27開始支援 WebSocket,從7.0.47開始支援JSR-356
websocket客戶端:
在客戶端,沒有必要為 WebSockets 使用 JavaScript 庫。實現 WebSockets 的 Web 瀏覽器將通過 WebSockets 物件公開所有必需的客戶端功能(主要指支援 Html5 的瀏覽器)。
客戶端API:
以下 API 用於建立 WebSocket 物件。
var Socket = new WebSocket(url, [protocol] );
以上程式碼中的第一個引數 url, 指定連線的 URL。第二個引數 protocol 是可選的,指定了可接受的子協議。
WebSocket 屬性
以下是 WebSocket 物件的屬性。假定我們使用了以上程式碼建立了 Socket 物件:
屬性 | 描述 |
---|---|
Socket.readyState | 只讀屬性 readyState 表示連線狀態,可以是以下值:0 - 表示連線尚未建立。1 - 表示連線已建立,可以進行通訊。2 - 表示連線正在進行關閉。3 - 表示連線已經關閉或者連線不能開啟。 |
Socket.bufferedAmount | 只讀屬性 bufferedAmount 已被 send() 放入正在佇列中等待傳輸,但是還沒有發出的 UTF-8 文字位元組數。 |
WebSocket 事件
以下是 WebSocket 物件的相關事件。假定我們使用了以上程式碼建立了 Socket 物件:
事件 | 事件處理程式 | 描述 |
---|---|---|
open | Socket.onopen | 連線建立時觸發 |
message | Socket.onmessage | 客戶端接收服務端資料時觸發 |
error | Socket.onerror | 通訊發生錯誤時觸發 |
close | Socket.onclose | 連線關閉時觸發 |
WebSocket 方法
以下是 WebSocket 物件的相關方法。假定我們使用了以上程式碼建立了 Socket 物件:
方法 | 描述 |
---|---|
Socket.send() | 使用連線傳送資料 |
Socket.close() | 關閉連線 |
客戶端例項:
<%-- Created by IntelliJ IDEA. User: zhen Date: 2018/12/10 Time: 17:36 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>welcome page</title> </head> <body> welcome to ssm all annotation project! <input id="text" type="text"/> <button onclick="send()">傳送訊息</button> <hr/> <button onclick="closeWebSocket()">關閉webSocket連線</button> <hr/> <div id="message"></div> </body> <script type="text/javascript"> var webSocket = null; //判斷當前瀏覽器是否支援webSocket if ('WebSocket' in window) { webSocket = new WebSocket("ws://localhost:8080/spring4webSocket/myHandler") } else { alert("當前瀏覽器 Not support webSocket"); } webSocket.onerror = onError; webSocket.onopen = onOpen; webSocket.onmessage = onMessage; webSocket.onclose = onClose; function onError() { setMessageInnerHTML("WebSocket連線發生錯誤"); } function onOpen() { setMessageInnerHTML("WebSocket連線成功"); } function onMessage(event){ //將接受到的資料直接輸出 setMessageInnerHTML(event.data); } function onClose() { setMessageInnerHTML("webSocket連線關閉"); } function setMessageInnerHTML(message) { var messageDiv = document.getElementById("message"); messageDiv.innerHTML = messageDiv.innerHTML + "<br/>" + message; } //監聽串列埠關閉事件,當視窗關閉時,主動去關閉webSocket連線,防止還沒斷開就關閉視窗,srever端會拋異常 window.onbeforeunload = function (ev) { closeWebSocket(); } function closeWebSocket(){ webSocket.close(); } //傳送訊息 function send() { var message = document.getElementById("text").value; webSocket.send(message); } </script> </html>客戶端例項
服務端(java):
基於servlet api:
1、匯入有關jar包
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
API:
@ServerEnpoint 宣告webSocket服務端,指明對映url
@OnMessage 標註接收到訊息執行監聽方法
@OnOpen 標註開啟連線時候執行監聽方法
@OnClose 標註關閉連線時執行監聽方法
@OnError 標註連線異常時執行監聽方法
服務端例項:
package com.zhen.websocket; /** * @author zhen * @Date 2018/12/6 10:29 */ import java.io.*; import java.util.*; import javax.websocket.EncodeException; import javax.websocket.OnClose; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import javax.websocket.OnMessage; import javax.websocket.OnOpen; // @ServerEndpoint 註解允許你宣告一個WeoSocket,定義url對映,定義編碼和解碼 @ServerEndpoint( value="/story/notifications", encoders={StickerEncoder.class}, decoders={StickerDecoder.class} ) public class StoryWebSocket { private static final List<Sticker> stickers = Collections.synchronizedList(new LinkedList<Sticker>()); private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>()); @OnMessage public void onMessage(Session session, Sticker sticker){ // 有訊息從客戶端傳送過來,儲存到列表中,然後通知所有的客戶端 stickers.add(sticker); for(Session openSession : sessions){ try { openSession.getBasicRemote().sendObject(sticker); } catch (IOException | EncodeException e) { sessions.remove(openSession); } } } @OnOpen public void onOpen(Session session) throws IOException, EncodeException{ // 有新的客戶端連線時,儲存此客戶端的session,並且把當前所有的sticker傳送給它 sessions.add(session); for(Sticker sticker : stickers){ session.getBasicRemote().sendObject(sticker); } } @OnClose public void onClose(Session session){ // 有客戶端斷開連線時 ,從session列表中移除此客戶端的session sessions.remove(session); } }服務端例項
看的有些混亂不能很好理解的時候就敲一些例子,功能出來就更容易理解了。
跟著下面兩篇教程的案例
- Using WebSocket for Real-Time Communication in Java Platform, Enterpise Edition 7
- Java EE 7: Building Web Applications with WebSocket, JavaScript and HTML5
package com.zhen.websocket; /** * @author zhen * @Date 2018/12/6 10:28 */ public class Sticker { private int x; private int y; private String image; public Sticker() { } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } } package com.zhen.websocket; import javax.json.JsonObject; import javax.json.JsonReader; import javax.json.spi.JsonProvider; import javax.websocket.DecodeException; import javax.websocket.Decoder; import javax.websocket.EndpointConfig; import java.io.IOException; import java.io.Reader; /** * @author zhen * @Date 2018/12/6 11:08 * 用來讀取webSocket流中的資料使用Decode.TextStream介面。 這個介面允許你讀取資料從socket中通過JsonReader物件,構造傳入Reader物件,並且轉換客戶端返回文字JSON資料 */ public class StickerDecoder implements Decoder.TextStream<Sticker>{ // Do not create a JsonReader object. To create readers and writes, use the // JsonProvider class. @Override public void init(EndpointConfig config) { // TODO Auto-generated method stub } @Override public void destroy() { // TODO Auto-generated method stub } @Override public Sticker decode(Reader reader) throws DecodeException, IOException { JsonProvider provider = JsonProvider.provider(); JsonReader jsonReader = provider.createReader(reader); JsonObject jsonSticker = jsonReader.readObject(); Sticker sticker = new Sticker(); sticker.setX(jsonSticker.getInt("x")); sticker.setY(jsonSticker.getInt("y")); sticker.setImage(jsonSticker.getString("sticker")); return sticker; } } package com.zhen.websocket; import javax.json.JsonObject; import javax.json.JsonWriter; import javax.json.spi.JsonProvider; import javax.websocket.EncodeException; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; import java.io.IOException; import java.io.Writer; /** * @author zhen * @Date 2018/12/6 10:59 * 這個類編碼Sticker物件並且傳遞給WebSocket伺服器通過寫入流中 */ public class StickerEncoder implements Encoder.TextStream<Sticker> { @Override public void init(EndpointConfig config) { // TODO Auto-generated method stub } @Override public void destroy() { // TODO Auto-generated method stub } @Override public void encode(Sticker sticker, Writer writer) throws EncodeException, IOException { JsonProvider provider = JsonProvider.provider(); JsonObject jsonSticker = provider.createObjectBuilder() .add("action", "add") .add("x", sticker.getX()) .add("y", sticker.getY()) .add("sticker", sticker.getImage()) .build(); JsonWriter jsonWriter = provider.createWriter(writer); jsonWriter.write(jsonSticker); } } package com.zhen.websocket; /** * @author zhen * @Date 2018/12/6 10:29 */ import java.io.*; import java.util.*; import javax.websocket.EncodeException; import javax.websocket.OnClose; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import javax.websocket.OnMessage; import javax.websocket.OnOpen; // @ServerEndpoint 註解允許你宣告一個WeoSocket,定義url對映,定義編碼和解碼 @ServerEndpoint( value="/story/notifications", encoders={StickerEncoder.class}, decoders={StickerDecoder.class} ) public class StoryWebSocket { private static final List<Sticker> stickers = Collections.synchronizedList(new LinkedList<Sticker>()); private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>()); @OnMessage public void onMessage(Session session, Sticker sticker){ // 有訊息從客戶端傳送過來,儲存到列表中,然後通知所有的客戶端 stickers.add(sticker); for(Session openSession : sessions){ try { openSession.getBasicRemote().sendObject(sticker); } catch (IOException | EncodeException e) { sessions.remove(openSession); } } } @OnOpen public void onOpen(Session session) throws IOException, EncodeException{ // 有新的客戶端連線時,儲存此客戶端的session,並且把當前所有的sticker傳送給它 sessions.add(session); for(Sticker sticker : stickers){ session.getBasicRemote().sendObject(sticker); } } @OnClose public void onClose(Session session){ // 有客戶端斷開連線時 ,從session列表中移除此客戶端的session sessions.remove(session); } } var socket = null; function initialize() { var canvas = document.getElementById("board"); var ctx = canvas.getContext("2d"); var img = document.getElementById("background_img"); ctx.drawImage(img, 0, 0); socket = new WebSocket("ws://localhost:8080/stickStory/story/notifications"); socket.onmessage = onSocketMessage; } function drag(ev) { var bounds = ev.target.getBoundingClientRect(); var draggedSticker = { sticker: ev.target.getAttribute("data-sticker"), offsetX: ev.clientX - bounds.left, offsetY: ev.clientY - bounds.top }; var draggedText = JSON.stringify(draggedSticker); ev.dataTransfer.setData("text", draggedText); } function drop(ev) { ev.preventDefault(); var bounds = document.getElementById("board").getBoundingClientRect(); var draggedText = ev.dataTransfer.getData("text"); var draggedSticker = JSON.parse(draggedText); var stickerToSend = { action: "add", x: ev.clientX - draggedSticker.offsetX - bounds.left, y: ev.clientY - draggedSticker.offsetY - bounds.top, sticker: draggedSticker.sticker }; socket.send(JSON.stringify(stickerToSend)); log("Sending Object " + JSON.stringify(stickerToSend)); } function allowDrop(ev) { ev.preventDefault(); } function onSocketMessage(event) { if (event.data) { var receivedSticker = JSON.parse(event.data); log("Received Object: " + JSON.stringify(receivedSticker)); if (receivedSticker.action === "add") { var imageObj = new Image(); imageObj.onload = function() { var canvas = document.getElementById("board"); var context = canvas.getContext("2d"); context.drawImage(imageObj, receivedSticker.x, receivedSticker.y); }; imageObj.src = "resources/stickers/" + receivedSticker.sticker; } } } function toggleLog() { var log = document.getElementById("logContainer"); if (!log.getAttribute("style")) { log.setAttribute("style", "display:block;"); } else { log.setAttribute("style", ""); } } var logCount = 0; function log(logstr) { var logElement = document.getElementById("log"); logElement.innerHTML = "<b>[" + logCount + "]: </b>" + logstr + "<br>" + logElement.innerHTML; logCount++; } window.onload = initialize; <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html> <html> <head> <title>Sticker Story</title> <link href="resources/styles.css" rel="stylesheet" type="text/css" > <script src="resources/story-page.js" type="text/javascript"></script> </head> <body> <header> <h1>Sticker Story Book</h1> </header> <nav> Drag stickers from the left bar to the canvas. </nav> <aside> <h2>Stickers</h2> <div id="stickerContainer"> <img src="resources/stickers/bear.png" data-sticker="bear.png" style="float:left" draggable="true" ondragstart="drag(event);" > <img src="resources/stickers/chicken.png" data-sticker="chicken.png" style="float:left" draggable="true" ondragstart="drag(event);" > <img src="resources/stickers/leopard.png" data-sticker="leopard.png" style="float:left" draggable="true" ondragstart="drag(event);" > <img src="resources/stickers/monkey.png" data-sticker="monkey.png" style="float:left" draggable="true" ondragstart="drag(event);" > <img src="resources/stickers/horse.png" data-sticker="horse.png" style="float:left" draggable="true" ondragstart="drag(event);" > <img src="resources/stickers/tiger.png" data-sticker="tiger.png" style="float:left" draggable="true" ondragstart="drag(event);" > </div> </aside> <div id="content"> <canvas id="board" width="1000" height="580" ondrop="drop(event);" ondragover="allowDrop(event);"> Canvas Not Supported. </canvas> <img src="resources/canvas2.png" id="background_img" width="1000" height="580" style="display:none;"/> </div> <footer> <small>Made with HTML5 + WebSockets and JSON</small> <ol> <li onclick="toggleLog();">Log</li> </ol> </footer> <div id="logContainer"> <h2>log</h2> <div id="log"></div> </div> </body> </html> <?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhen</groupId> <artifactId>StickStory</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <!-- Servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <!-- JSON工具包 --> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.json</artifactId> <version>1.0.4</version> </dependency> </dependencies> <build> <plugins> <!-- 編譯外掛 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- tomcat 外掛 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/stickStory</path> </configuration> </plugin> </plugins> </build> </project>第一篇敲的專案程式碼
這裡接受返回訊息用到了轉換器,接受物件型別json返回物件型別json
實現釋出訂閱模式
專案目錄如下:
第二篇敲的專案程式碼:
package com.zhen.model; /** * @author zhen * @Date 2018/12/6 15:30 */ public class Device { private int id; private String name; private String status; private String type; private String description; public Device() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } } package com.zhen.websocket; import com.zhen.model.Device; import javax.enterprise.context.ApplicationScoped; import javax.json.JsonObject; import javax.json.spi.JsonProvider; import javax.websocket.Session; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; /** * @author zhen * @Date 2018/12/6 15:50 */ @ApplicationScoped public class DeviceSessionHandler { private final Set<Session> sessions = new HashSet<>(); private final Set<Device> devices = new HashSet<>(); private static AtomicInteger deviceId = new AtomicInteger(0); public void addSession(Session session) { sessions.add(session); for (Device device : devices) { JsonObject addMessage = createAndMessage(device); sendToSession(session, addMessage); } } public void removeSession(Session session) { sessions.remove(session); } public void addDevice(Device device) { device.setId(deviceId.incrementAndGet()); devices.add(device); JsonObject addMessage = createAndMessage(device); sendToAllConnectedSessions(addMessage); } public void removeDevice(int id) { Device device = getDeviceById(id); if (device != null) { devices.remove(device); JsonProvider provider = JsonProvider.provider(); JsonObject removeMessage = provider.createObjectBuilder() .add("action", "remove") .add("id", id) .build(); sendToAllConnectedSessions(removeMessage); } } public void toggleDevice(int id) { JsonProvider provider = JsonProvider.provider(); Device device = getDeviceById(id); if (device != null) { if ("On".equals(device.getStatus())) { device.setStatus("Off"); } else { device.setStatus("On"); } JsonObject updateDevMessage = provider.createObjectBuilder() .add("action", "toggle") .add("id", device.getId()) .add("status", device.getStatus()) .build(); sendToAllConnectedSessions(updateDevMessage); } } public List<Device> getDevices(){ return new ArrayList<>(devices); } public Device getDeviceById(int id) { for (Device device : devices) { if (device.getId() == id) { return device; } } return null; } public JsonObject createAndMessage(Device device) { JsonProvider provider = JsonProvider.provider(); JsonObject addMessage = provider.createObjectBuilder() .add("action", "add") .add("name", device.getName()) .add("type", device.getType()) .add("status", device.getStatus()) .add("description", device.getDescription()) .build(); return addMessage; } private void sendToAllConnectedSessions(JsonObject message) { for (Session session : sessions) { sendToSession(session, message); } } private void sendToSession(Session session, JsonObject message) { try{ session.getBasicRemote().sendText(message.toString()); } catch (IOException ex) { sessions.remove(session); Logger.getLogger(DeviceSessionHandler.class.getName()).log(Level.SEVERE, null, ex); } } } package com.zhen.websocket; import com.zhen.model.Device; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.json.Json; import javax.json.JsonObject; import javax.json.JsonReader; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.StringReader; import java.util.logging.Level; import java.util.logging.Logger; /** * @author zhen * @Date 2018/12/6 15:32 */ @ApplicationScoped @ServerEndpoint("/actions") public class DeviceWebSocketServer { @Inject private DeviceSessionHandler sessionHandler = new DeviceSessionHandler(); @OnOpen public void open(Session session) { sessionHandler.addSession(session); } @OnClose public void close(Session session) { sessionHandler.removeSession(session); } @OnError public void onError(Throwable error) { Logger.getLogger(DeviceWebSocketServer.class.getName()).log(Level.SEVERE, null, error); } @OnMessage public void handleMessage(Session session, String message) { try(JsonReader reader = Json.createReader(new StringReader(message))){ JsonObject jsonMessage = reader.readObject(); if ("add".equals(jsonMessage.getString("action"))) { Device device = new Device(); device.setName(jsonMessage.getString("name")); device.setDescription(jsonMessage.getString("description")); device.setType(jsonMessage.getString("type")); device.setStatus("Off"); sessionHandler.addDevice(device); } if ("remove".equals(jsonMessage.getString("action"))) { int id = (int) jsonMessage.getInt("id"); sessionHandler.removeDevice(id); } if ("toggle".equals(jsonMessage.getString("action"))) { int id = (int) jsonMessage.getInt("id"); sessionHandler.toggleDevice(id); } } } } <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html> <html> <head> <title>Index</title> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <link rel="stylesheet" href="style.css"> <script src="websocket.js"></script> </head> <body> <div id="wrapper"> <h1>Java WebSocket Home</h1> <p>Welcome to the Java WebSocket Home. Click the Add a device button to start adding devices.</p> <br/> <div id="addDevice"> <div class="button"><a href="#" onclick="showForm()">Add a device</a> </div> <form id="addDeviceForm"> <h3>Add a new device</h3> <span>Name: <input type="text" name="device_name" id="device_name"></span> <span> Type: <select id="device_type"> <option name="type" value="Appliance">Appliance</option> <option name="type" value="Electronics">Electronics</option> <option name="type" value="Lights">Lights</option> <option name="type" value="Other">Other</option> </select> </span> <span> Description:<br/> <textarea name="description" id="device_description" rows="2" cols="50"></textarea> </span> <input type="button" class="button" value="Add" onclick="formSubmit();"> <input type="reset" class="button" value="Cancel" onclick="hideForm();"> </form> </div> <br/> <h3>Currently connected devices:</h3> <div id="content"></div> </div> </body> </html> body { font-family: Arial, Helvetica, sans-serif; font-size: 80%; background-color: #1f1f1f; } #wrapper { width: 960px; margin: auto; text-align: left; color: #d9d9d9; } p { text-align: left; } .button { display: inline; color: #fff; background-color: #f2791d; padding: 8px; margin: auto; border-radius: 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; box-shadow: none; border: none; } .button:hover { background-color: #ffb15e; } .button a, a:visited, a:hover, a:active { color: #fff; text-decoration: none; } #addDevice { text-align: center; width: 960px; margin: auto; margin-bottom: 10px; } #addDeviceForm { text-align: left; width: 400px; margin: auto; padding: 10px; } #addDeviceForm span { display: block; } #content { margin: auto; width: 960px; } .device { width: 180px; height: 110px; margin: 10px; padding: 16px; color: #fff; vertical-align: top; border-radius: 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; display: inline-block; } .device.off { background-color: #c8cccf; } .device span { display: block; } .deviceName { text-align: center; font-weight: bold; margin-bottom: 12px; } .removeDevice { margin-top: 12px; text-align: center; } .device.Appliance { background-color: #5eb85e; } .device.Appliance a:hover { color: #a1ed82; } .device.Electronics { background-color: #0f90d1; } .device.Electronics a:hover { color: #4badd1; } .device.Lights { background-color: #c2a00c; } .device.Lights a:hover { color: #fad232; } .device.Other { background-color: #db524d; } .device.Other a:hover { color: #ff907d; } .device a { text-decoration: none; } .device a:visited, a:active, a:hover { color: #fff; } .device a:hover { text-decoration: underline; } window.onload = init; var socket = new WebSocket("ws://localhost:8080/webSocketHome/actions"); socket.onmessage = onMessage; function onMessage(event) { var device = JSON.parse(event.data); if (device.action === "add") { printDeviceElement(device); } if (device.action === "remove") { document.getElementById(device.id).remove(); //device.parentNode.removeChild(device); } if (device.action === "toggle") { var node = document.getElementById(device.id); var statusText = node.children[2]; if (device.status === "On") { statusText.innerHTML = "Status: " + device.status + " (<a href=\"#\" OnClick=toggleDevice(" + device.id + ")>Turn off</a>)"; } else if (device.status === "Off") { statusText.innerHTML = "Status: " + device.status + " (<a href=\"#\" OnClick=toggleDevice(" + device.id + ")>Turn on</a>)"; } } } function addDevice(name, type, description) { var DeviceAction = { action: "add", name: name, type: type, description: description }; socket.send(JSON.stringify(DeviceAction)); } function removeDevice(element) { var id = element; var DeviceAction = { action: "remove", id: id }; socket.send(JSON.stringify(DeviceAction)); } function toggleDevice(element) { var id = element; var DeviceAction = { action: "toggle", id: id }; socket.send(JSON.stringify(DeviceAction)); } function printDeviceElement(device) { var content = document.getElementById("content"); var deviceDiv = document.createElement("div"); deviceDiv.setAttribute("id", device.id); deviceDiv.setAttribute("class", "device " + device.type); content.appendChild(deviceDiv); var deviceName = document.createElement("span"); deviceName.setAttribute("class", "deviceName"); deviceName.innerHTML = device.name; deviceDiv.appendChild(deviceName); var deviceType = document.createElement("span"); deviceType.innerHTML = "<b>Type:</b> " + device.type; deviceDiv.appendChild(deviceType); var deviceStatus = document.createElement("span"); if (device.status === "On") { deviceStatus.innerHTML = "<b>Status:</b> " + device.status + " (<a href=\"#\" OnClick=toggleDevice(" + device.id + ")>Turn off</a>)"; } else if (device.status === "Off") { deviceStatus.innerHTML = "<b>Status:</b> " + device.status + " (<a href=\"#\" OnClick=toggleDevice(" + device.id + ")>Turn on</a>)"; //deviceDiv.setAttribute("class", "device off"); } deviceDiv.appendChild(deviceStatus); var deviceDescription = document.createElement("span"); deviceDescription.innerHTML = "<b>Comments:</b> " + device.description; deviceDiv.appendChild(deviceDescription); var removeDevice = document.createElement("span"); removeDevice.setAttribute("class", "removeDevice"); removeDevice.innerHTML = "<a href=\"#\" OnClick=removeDevice(" + device.id + ")>Remove device</a>"; deviceDiv.appendChild(removeDevice); } function showForm() { document.getElementById("addDeviceForm").style.display = ''; } function hideForm() { document.getElementById("addDeviceForm").style.display = "none"; } function formSubmit() { var form = document.getElementById("addDeviceForm"); var name = form.elements["device_name"].value; var type = form.elements["device_type"].value; var description = form.elements["device_description"].value; hideForm(); document.getElementById("addDeviceForm").reset(); addDevice(name, type, description); } function init() { hideForm(); } <?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhen</groupId> <artifactId>WebSocketHome</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <!-- Servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <!-- JSON工具包 --> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.json</artifactId> <version>1.0.4</version> </dependency> </dependencies> <build> <plugins> <!-- 編譯外掛 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- tomcat 外掛 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/webSocketHome</path> </configuration> </plugin> </plugins> </build> </project>第二篇敲的程式碼
此案例利用websocket實現了一套增刪改查
專案中使用了CDI註解,如@ApplicationScope,@Inject進行注入功能
專案結構:
spring的websocket支援:
spring4提供了對websocket的支援
<!-- spring-webSocket,不使用javaee7的api裡面了,使用spring的封裝 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>${spring.version}</version> </dependency>
服務端配置:
package com.zhen.spring_websocket.config; import com.zhen.spring_websocket.service.MyHandler; import com.zhen.spring_websocket.service.MyHandler1; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; /** * @author zhen * @Date 2018/12/10 18:34 */ @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(),"/myHandler"); registry.addHandler(myHandler1(),"/myHandler1").withSockJS(); } public WebSocketHandler myHandler() { return new MyHandler(); } public WebSocketHandler myHandler1() { return new MyHandler1(); } }
package com.zhen.spring_websocket.service; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.AbstractWebSocketHandler; import org.springframework.web.socket.handler.TextWebSocketHandler; import java.io.IOException; /** * @author zhen