javascript
WildFly上具有AngularJS的Java EE 7和Java WebSocket API(JSR 356)
這篇博客文章描述了用于WebSocket協議的Java API(JSR 356) (這是Java EE 7平臺的四個最新JSR之一),并提供了部署在WildFly 8上并可以在OpenShift上在線獲得的具體應用程序。
- [FR]版本的法語( HTML或PDF )在AngularJS上發布了基于Java API的示范性演示。
閱讀這篇文章后,您將能夠了解Arun Gupta對WebSocket技術可以做什么的定義。
“ WebSocket通過單個TCP為您提供雙向的全雙工通信通道。”
— Arun Gupta(Java EE布道士Chez Oracle)–英國Devoxx 2013
Java EE 7概述
Java平臺企業版于2013年6月在版本7(Java EE 7)中發布。 與先前的兩個版本(Java EE 5和Java EE 6)保持一致, Java EE 7始終建議簡化開發人員的工作。 此版本用3個主要目標裝飾了以前的版本:
- 包含HTML5 (WebSocket API,JSON-P API,JAX-RS)
- 為開發人員(JMS)提供更高的生產率
- 滿足企業需求 (批處理API,并發實用程序)
圖1. Java EE 7的三個目標
Java平臺企業版7(JSR 342)可以總結為:
- 4個最新規范: Java API for WebSocket 1.0 Java API for JSON Processing 1.0 , Batch Applications 1.0和Concurrency Utilities for Java EE 1.0
- 3個主要更新的規范: JMS 2.0 , JAX-RS 2.0和EL 3.0
- 和6個規范(進行了較小的更新): JPA 2.1 , Servlet 3.1 , EJB 3.2 , CDI 1.1 , JSF 2.2和Bean Validation 1.1
演示:AngularJS –在WildFly 8(OpenShift)上部署HTML5 / JSR-356 API應用程序
如果要立即查看它的外觀,可以訪問the online application其代碼將在本文中進行部分說明。 這個應用程序可以為您提供以下功能:
- 觀看(四分之一決賽美國公開賽2013年)在現場模式的一個或幾個網球比賽
- 點擊您要實時訪問的每個比賽
- 下注比賽的獲勝者
- 每當用戶下注相同的比賽時,計數器就會增加
您會說: “沒什么特別的!” ,而您是對的:)
乍一看,這聽起來像是當今許多應用程序中已經看到的東西,但是它所使用的技術確實很重要,因為,正如您將在下面看到的那樣,所有內容都基于新的WebSocket協議(ws:// ou)的標準。 wss://),而不是在“ HTTP hacking”上。
用于開發此應用程序的技術是:
- 前端: HTML5 , CSS ,帶有Bootstrap CSS和AngularJS Javascript (WebSocket API)
- 后端: Java API for WebSocket , EJB , JSON-P , JAX-RS
圖2.美國開放應用程序– WebSocket的實現(Java API和Javascript API)
不! 該演示不是聊天應用程序:)很明顯,“聊天演示”是首先想到的用于說明WebSocket技術使用的示例。 但是,還有許多其他用例,例如在線文本文檔上的協作工作或JavaOne 2013主題演講中展示的象棋這樣的在線游戲。
借助RedHat的云計算PaaS產品OpenShift ,該應用程序可在云上使用。 它已部署在WildFly 8.0.0-Beta1(正常認證的Java EE 7到2013年底)上。 要在OpenShit上設置WildFly之類的應用服務器,您只需閱讀Shekhar Gulati的博客文章
WebSocket(WS):不同于HTTP的新協議
HTTP是Web的標準協議,它在許多用例中非常有效,但是在交互式Web應用程序中卻有一些缺點 :
- 半雙工 :基于請求/響應模式,客戶端發送請求,服務器在發送響應之前執行處理,客戶端被迫等待服務器響應
- 詳細 :在HTTP請求和HTTP響應中,與消息相關的HTTP標頭中發送了大量信息
- 為了添加服務器推送模式,您需要使用解決方法(輪詢,長輪詢,Comet / Ajax),因為沒有標準
該協議并未針對在實時雙向通信方面有重大需求的大型應用進行優化。 這就是為什么新的WebSocket協議比HTTP提供更多高級功能的原因,因為它是:
- 基于1 unique TCP connection between 2 peers (而每個HTTP請求/響應都需要一個新的TCP連接)
- bidirectionnal :客戶端可以向服務器發送消息,服務器也可以向客戶端發送消息
- full-duplex :客戶端可以將多個消息發送到服務器,也可以將服務器發送到客戶端,而無需等待彼此的響應
術語“ 客戶端”僅用于定義啟動連接的客戶端 。 建立連接后,客戶端和服務器將成為具有相同容量的對等端。
WebSocket協議原本打算成為HTML5規范的一部分,但是隨著HTML5將于2014年正式發布,WebSocket協議以及HTTP協議最終都由IETF規范和RFC 6455設置 。
如下圖所示, WebSocket協議在兩個階段起作用 :
圖3. WebSocket協議如何工作
開幕握手
打開握手階段是發起連接的一個請求 (對等客戶端)和對等服務器之間的唯一HTTP請求/響應 。 此HTTP交換是特定的,因為它使用HTTP規范中定義的升級概念。 原理很簡單: 升級HTTP允許客戶端要求服務器更改通信協議,從而確保客戶端和服務器可以使用HTTP以外的協議進行討論。
例子1. HTTP握手示例請求
GET /usopen/matches/1234 HTTP/1.1 Host: wildfly-mgreau.rhcloud.com:8000 Upgrade: websocket Connection: Upgrade Origin: http://wildfly-mgreau.rhcloud.com Sec-WebSocket-Key:0EK7XmpTZL341oOh7x1cDw== Sec-WebSocket-Version:13 第1行:需要HTTP GET方法和HTTP 1.1版本
第2行:用于WebSocket連接的主機
第3行:請求升級到WebSocket協議 第4行:請求從HTTP升級到另一個協議
例子2. HTTP握手響應樣本
HTTP/1.1 101 Switching Protocols Connection:Upgrade Sec-WebSocket-Accept:SuQ5/hh0kStSr6oIzDG6gRfTx2I= Upgrade:websocket 第1行:HTTP響應代碼101:服務器兼容并接受通過其他協議發送消息
第4行:接受升級到WebSocket協議
當端點服務器批準了從HTTP到WebSocket協議的升級請求時,就不再可以使用HTTP通信,所有交換都必須通過WebSocket協議進行。
數據傳輸
一旦握手被批準,就可以使用WebSocket協議。 在對等服務器端以及對等客戶端端都有一個開放的連接,調用回調處理程序以啟動通信。
現在可以開始數據傳輸 ,因此兩個對等方可以雙向和全雙工通信方式交換消息。
如圖3所示 ,對peer server可以發送多條消息( 在此示例中:每個得分點1條消息,每次用戶在此游戲下注時每條消息1條,比賽結束時每條消息1條消息 ),而無需發送任何消息peer client響應,對等客戶端也可以隨時發送消息( 在此示例中:押注比賽獲勝者 )。 每個對等方都可以發送特定的消息以關閉連接。
使用Java EE7平臺,對peer server side代碼是用Java編寫的,而對peer client side代碼是用Java或Javascript編寫的。
關閉握手
這個階段可以由雙方發起 。 想要關閉通信的對等方需要發送一個關閉控制幀,并且它也會收到一個關閉控制幀作為響應。
WebSocket Javascript API(客戶端)
要使用WebSocket協議從Web應用程序與服務器進行通信,必須使用客戶端Javascript API 。 定義此API是W3C的角色。 JavaScript WebSocket API的W3C規范正在最終確定。 WebSocket接口提供以下功能:
- 一個屬性,用于定義到服務器端點的連接URL( url )
- 知道連接狀態的屬性( readyState :CONNECTING,OPEN,CLOSING,CLOSED)
- 與WebSocket生命周期有關的一些事件處理程序 ,例如:
- 當新連接打開時,將調用事件處理程序onopen
- 可以將不同類型的流(文本,二進制)發送到端點服務器的方法( send(DOMString data) , send(Blob data) )
例子3.來自http://websocket.org的 JavaScript源代碼例子
var wsUri = "ws://echo.websocket.org/";function testWebSocket() {websocket = new WebSocket(wsUri);websocket.onopen = function(evt) { onOpen(evt) };websocket.onclose = function(evt) { onClose(evt) };websocket.onmessage = function(evt) { onMessage(evt) };websocket.onerror = function(evt) { onError(evt) }; } }function onOpen(evt) {writeToScreen("CONNECTED");doSend("WebSocket rocks"); } function onClose(evt) {writeToScreen("DISCONNECTED"); } function onMessage(evt) {writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data+'</span>');websocket.close(); }function onError(evt) {writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data); } function doSend(message) {writeToScreen("SENT: " + message);websocket.send(message); }JSR 386:用于WebSocket協議的Java API
由于W3C定義了如何在Javascript中使用WebSocket,因此Java Communitee Process(JCP)通過JSR 386在Java世界中進行了相同的操作。JSR356 為WebSocket協議定義了Java API,該協議是Java EE Web Profile的一部分,并提供了有能力 :
- 創建一個WebSocket Endpoint (服務器或客戶端),該名稱是可以通過WebSocket協議進行通信的Java組件的名稱
- 注釋或程序化方法的選擇
- 通過此協議發送和使用消息控件,文本或二進制
- 將消息作為完整消息或部分消息序列進行管理
- 配置和管理WebSocket會話 (超時,Cookie…)
開源JSR-356 RI(參考實現)是Tyrus項目
WebSocket服務器端點
將普通舊Java對象(PO??JO)轉換為服務器WebSocket端點 (即能夠處理來自同一URI的不同客戶的請求) 非常容易,因為您只需用@ServerEndpoint注釋Java類,并用@注釋一種方法即可。 OnMessage :
import javax.websocket.OnMessage; import javax.websocket.ServerEndpoint;@ServerEndpoint("/echo") public class EchoServer {@OnMessage public String handleMessage(String message){return "Thanks for the message: " + message;}} 第04行:@ServerEndpoint將此POJO轉換為WebSocket端點,為將訪問URI設置為此端點,必須使用value屬性
第07行:將為每個收到的消息調用handleMessage方法
注解
此Java API提供了幾種與WebSocket協議完全兼容的注釋:
| @ServerEndpoint | 聲明服務器端點 |
| @ClientEndpoint | 聲明客戶端端點 |
| @OnOpen | 聲明此方法處理打開事件 |
| @OnMessage | 聲明此方法處理Websocket消息 |
| @OnError | 聲明此方法處理錯誤 |
| @OnClose | 聲明此方法處理WebSocket關閉事件 |
@ServerEndpoint屬性在下面列出:
- 值
- 相對URI或模板URI(例如:“ / echo”,“ / matches / {match-id}”)
- 解碼器
- 消息解碼器類名列表
- 編碼器
- 消息編碼器類名列表
- 子協議
- 支持的子協議的名稱列表(例如:http://wamp.ws)
編碼器和解碼器
如本文前面所述,端點服務器可以接收消息中不同類型的內容:文本格式(JSON,XML…)或二進制格式的數據。
為了有效地管理來自對等客戶端或應用程序業務代碼中的對等客戶端的消息,可以創建Encoders和Decoders Java類。
無論采用哪種轉換算法,都可以進行轉換:
- 業務POJO以所需的通信格式(JSON,XML,Binary…)流動
- 以特定格式(JSON,XML ..)流入業務POJO
因此,應用程序代碼的結構使得業務邏輯不受對等服務器和對等客戶端流之間交換的消息的類型和格式的影響。
本文后面將提供一個具體示例。
WebSocket客戶端端點
該Java API還提供了對創建客戶端Java端點的支持。
例子4. Java客戶端端點樣本
@ClientEndpoint public class HelloClient {@OnMessagepublic String message(String message){// code} }WebSocketContainer c = ContainerProvider.getWebSocketContainer(); c.connectToServer(HelloClient.class, "hello");美國公開賽
該示例應用程序被部署為使用Apache Maven構建的WAR結果。 除了傳統的管理WebSocket生命周期,發送消息的工作流程還如下:
- 每個對等客戶端可以連接1或4個實時比賽
- 每個對等客戶端都可以斷開匹配
- 在比賽的每個點,連接到該比賽的客戶端將接收數據(得分,服務…)
- 對等客戶可能會發送一條消息,押注比賽的獲勝者
- 每次一個對等客戶下注一場比賽,所有其他在相同比賽中下注的對等客戶都會收到一條消息,其中包含投注者總數
- 在比賽結束時, 對等客戶押注這場比賽,會收到一條消息,其中包含獲勝者的姓名和一條特定消息
所有消息均以JSON格式交換
項目布局如下:
例子5. Maven項目結構
+ src/main/java|+ com.mgreau.wildfly.websocket|+ decoders|- MessageDecoder.java |+ encoders |- BetMessageEncoder.java|- MatchMessageEncoder.java|+ messages |- BetMessage.java|- MatchMessage.java|- Message.java|+ rest |- RestApplication.java|- TournamentREST.java|- MatchEndpoint.java |- StarterService.java |- TennisMatch.java + src/main/resources + scr/main/webapp|+ css|+ images|+ js|+ live |- app.js|- controllers.js|- directives.js|- services.js|- websocket.js |+ templates|- bet.html|- match.html|- msg.html|- index.html|- live.html pom.xml 第04行:解碼從對等客戶端 (關于獲勝者的賭注)發送到POJO( BetMessage )的JSON消息
第05行:以JSON格式編碼(通過JSON-P),有關獲勝者的所有消息以及對等客戶端的比賽詳細信息
第08行:POJO處理對等體之間發送的消息 第12行:REST端點,列出所有比賽的比賽 第15行:應用程序WebSocket服務器端點( 對等服務器 ) 第16行:EJB @Startup,以便在部署時初始化此應用程序 第17行:POJO處理有關比賽的信息 第23行:AngularJS文件通過REST和WebSocket調用處理多個匹配項(live.html) 第28行:包含用于WebSocket協議的Javascript API實現的文件,用于處理簡單情況下的客戶端通信(index.html)
Java EE 7 API的Maven依賴關系
例子6.帶有Java EE 7依賴關系的pom.xml
<project> ... <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- Java EE 7 --><javaee.api.version>7.0</javaee.api.version> </properties<dependencies><dependency><groupId>javax</groupId> <artifactId>javaee-api</artifactId><version>${javaee.api.version}</version><scope>provided</scope></dependency> </dependencies> ... </project>第11行:使用Java EE 7依賴關系以便能夠在多個Java EE應用程序服務器(WildFly,Glassfish…)中部署同一應用程序而無需更改代碼,這一點很重要 。
添加服務器端點
該端點可以接收有關下注比賽獲勝者的消息(由match-id標識),并且還可以向對等客戶端發送有關比賽過程和下注的所有信息。
例子7.服務器端點:MatchEndpoint.java
@ServerEndpoint(value = "/matches/{match-id}", decoders = { MessageDecoder.class }, encoders = { MatchMessageEncoder.class, BetMessageEncoder.class } ) public class MatchEndpoint {private static final Logger logger = Logger.getLogger("MatchEndpoint");/** All open WebSocket sessions */static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());/** Handle number of bets by match */static Map<String, AtomicInteger> nbBetsByMatch = new ConcurrentHashMap<>();@Inject StarterService ejbService;@OnOpenpublic void openConnection(Session session,@PathParam("match-id") String matchId) { session.getUserProperties().put(matchId, true);peers.add(session);//Send live result for this matchsend(new MatchMessage(ejbService.getMatches().get(matchId)), matchId);}public static void send(MatchMessage msg, String matchId) {try {/* Send updates to all open WebSocket sessions for this match */for (Session session : queue) {if (Boolean.TRUE.equals(session.getUserProperties().get(matchId))){if (session.isOpen()){session.getBasicRemote().sendObject(msg); }}}} catch (IOException | EncodeException e) {logger.log(Level.INFO, e.toString());}}public static void sendBetMessage(Session session, BetMessage betMsg, String matchId){try {betMsg.setNbBets(nbBetsByMatch.get(matchId).get());session.getBasicRemote().sendObject(betMsg);logger.log(Level.INFO, "BetMsg Sent: {0}", betMsg.toString());} catch (IOException | EncodeException e) {logger.log(Level.SEVERE, e.toString());}}@OnMessagepublic void message(final Session session, BetMessage msg, @PathParam("match-id") String matchId) {session.getUserProperties().put("bet", msg.getWinner());//Send betMsg with bet countif (!nbBetsByMatch.containsKey(matchId)){nbBetsByMatch.put(matchId, new AtomicInteger());}nbBetsByMatch.get(matchId).incrementAndGet();sendBetMessages(null, matchId, false);}@OnClosepublic void closedConnection(Session session,@PathParam("match-id") String matchId) {if (session.getUserProperties().containsKey("bet")){nbBetsByMatch.get(matchId).decrementAndGet();sendBetMessages(null, matchId, false);}/* Remove this connection from the queue */peers.remove(session);} ... } 第02行:由于應用程序上下文根為/ usopen ,因此訪問此端點的URI的最終URL如下所示: ws://<host>:<port>/usopen/matches/1234
第03行: MessageDecoder將傳入的JSON流(約等于贏家的賭注)轉換為POJO BetMessage
第4行:這2個編碼器增加了將MatchMessage POJO和BetMessage POJO轉換為JSON格式消息的功能 第20行: @PathParam批注允許提取WebSocket請求的一部分并將值(id匹配)作為方法的參數傳遞,對于每個匹配,可以管理多個客戶端進行的多個匹配。 第34行:向連接的對等方發送有關比賽過程的消息。 多虧了MatchMessageEncoder對象,只需傳遞MatchMessage對象即可。 第55行:由于使用了MessageDecoder對象,因此可以處理接收到的有關贏家押注的消息 ,該方法的參數之一是BetMessage對象。
編碼和解碼消息
要對同位體之間交換的消息進行編碼或解碼,只需根據消息類型(文本,二進制)和處理方向(編碼,解碼)實現適當的接口,然后重新定義關聯的方法。
在下面的示例中,它是MatchMessage POJO到JSON格式的編碼器 。 用于執行此處理的API也是Java EE 7發行的新API: 用于JSON Processiong(JSON-P)的Java API
例子8.文本編碼器:MatchMessageEncoder.java
public class MatchMessageEncoder implements Encoder.Text<MatchMessage> {@Overridepublic String encode(MatchMessage m) throws EncodeException {StringWriter swriter = new StringWriter();try (JsonWriter jsonWrite = Json.createWriter(swriter)) {JsonObjectBuilder builder = Json.createObjectBuilder();builder.add("match",Json.createObjectBuilder().add("serve", m.getMatch().getServe()).add("title", m.getMatch().getTitle())...}jsonWrite.writeObject(builder.build());}return swriter.toString();} }HTML5 Web客戶端(單個匹配– index.html)
此應用程序的index.html頁面加載websocket.js文件以實現Javascript WebSocket API,從而與Java Server Endpoint進行交互。 此頁面僅處理一次匹配。
例子9.在websocket.js中實現的API Javascript
var wsUrl; if (window.location.protocol == 'https:') { wsUrl = 'wss://' + window.location.host + ':8443/usopen/matches/1234'; } else {wsUrl = 'ws://' + window.location.host + ':8000/usopen/matches/1234'; }function createWebSocket(host) {if (!window.WebSocket) { ...} else {socket = new WebSocket(host); socket.onopen = function() {document.getElementById("m1-status").innerHTML = 'CONNECTED...';};socket.onclose = function() {document.getElementById("m1-status").innerHTML = 'FINISHED';};...socket.onmessage = function(msg) {try {console.log(data);var obj = JSON.parse(msg.data); if (obj.hasOwnProperty("match")){ //titlem1title.innerHTML = obj.match.title;// commentsm1comments.value = obj.match.comments;// serveif (obj.match.serve === "player1") {m1p1serve.innerHTML = "S";m1p2serve.innerHTML = "";} else {m1p1serve.innerHTML = "";m1p2serve.innerHTML = "S";}..}...} catch (exception) {data = msg.data;console.log(data);}}} } 第02行:根據當前使用的HTTP協議(是否安全)選擇適當的WebSocket協議
第09行:檢查瀏覽器是否支持WebSocket API
第12行:創建WebSocket對象 第23行:嘗試將對等服務器發送的JSON消息解析為onmessage Event Handler調用的函數 第24行:檢查接收到的對象類型(MatchMessage或BetMessage)以對DOM進行適當處理
要了解哪些瀏覽器與WebSocket API兼容, 請訪問網站caniuse.com 。 如今,除了Android和Opera Mini瀏覽器外,所有最新版本的瀏覽器都兼容,二者僅占Web流量的3%。
AngularJS客戶端(幾個匹配項– live.html)
正如我們在本文開頭所看到的,用于處理多次匹配的版本是在客戶端使用AngularJS開發的。 因此,有4個JS文件包含:
- app.js :僅定義TennisApp角度應用程序
- controllers.js :TournamentCtrl控制器
- directives.js :
- bet指令和bet.html模板以顯示投注者數量和當前投注
- services.js :
- WebSocketService:通過回調處理WebSocket生命周期
這篇文章不是有關AngularJS的教程,因為這是我第一個使用此框架的應用程序。 但這是在客戶端處理多個匹配項的快速解決方案。 您可以閱讀以下3篇文章,以更好地理解JS代碼: 法語的 指令以及AngularJS 指令的重構和AngularJS WebSocket服務示例
Github上的源代碼
您可以在https://github.com/mgreau/javaee7-websocket Github上分叉此項目
該示例應用程序是基本的,可能會有很多改進,例如在其他條件上下注...
從技術上講,一個有趣的功能是根據每個獲勝點的坐標創建一種新的下注類型。 只需通過HTML5 Canvas API繪制背景并管理用戶選擇的坐標(例如獲勝點),然后與獲勝者的實際坐標進行比較即可。
構建和部署WAR
先決條件:
- JDK 7
- Apache Maven 3.0.4以上
- Java EE 7應用服務器(WildFly 8)
為了構建WAR,您只需執行以下Maven命令即可;
mvn clean package如果您的應用服務器是WildFly,則可以使用以下命令快速部署WAR(必須啟動WildFly):
mvn jboss-as:deploy然后可以在以下位置找到usopen應用程序:
- http:// localhost:8080 / usopen /僅使用本機Javascript的簡單情況
- http:// localhost:8080 / usopen / matches用于具有多次匹配和AngularJS的版本
WildFly 8使用其Web Server called Undertow新Web Server called Undertow來代替Tomcat。
我沒有在Glassfish 4上測試此應用程序,但是由于我僅使用Java EE 7 API依賴項,因此它可以與相同的代碼一起使用而不會出現問題。 讓我知道您是否對GlassFish有麻煩。
基準測試:WebSocket VS REST
為了獲得有關此新協議性能的一些指標,Arun Gupta開發了一個應用程序,該應用程序可以比較 WebSocket代碼和REST代碼執行的相同處理的執行時間 。
每個終結點(REST終結點和WebSocket終結點)都只是執行“回顯”,因此它們僅返回接收到的流。 應用程序的Web界面允許您定義消息的大小以及在測試結束之前必須發送消息的次數。
如下所示的基準測試結果非常雄辯:
| 發送10個1字節的消息 | 220毫秒(63毫秒)* | 7毫秒(29毫秒)* |
| 發送10個字節的100條消息 | 986毫秒(587毫秒)* | 57毫秒(74毫秒)* |
| 發送100個字節的1000條消息 | 10210毫秒(4 636毫秒)* | 179毫秒(288毫秒)* |
| 發送1000個字節的5000條消息 | 54449毫秒(18049毫秒)* | 1202毫秒(2862毫秒)* |
()*之間的值表示在具有默認配置的WildFly 8.0.0-beta1的筆記本電腦(MacBook Pro 2013 i5 – 8Go – 128SSD)上進行的相同測試。
關于WebSocket的參考
我特別推薦Arun Gupta的會議,這些會議使您可以在不到1小時的時間內發現并了解WebSocket技術以及適用于WebSocket的Java API。
有關更多高級信息,理想的是IETF,W3C和Java規范。
- RFC 6455:WebSocket協議 – IETF規范
- W3C:WebSocket API – W3C規范 (候選推薦)
- JSR 356:用于WebSocket協議的Java API – Java規范
- 采用JSR – JSR 356
- Java EE 7和WebSocket API – Arun Gupta的會議@ SF (從第46分鐘開始)
- WebSocket和SSE入門 – 2013年Devoxx UK的Arun Gupta會議
本文的結構是基于英國2013 Devoxx會議。
結論
本文通過一個具體示例介紹了隨Java EE 7一起發布的WebSocket協議,HTML5 WebSocket API和用于WebSocket的Java API 。 已經可以將WebSocket與Java框架(如Atmosphere)一起使用,但缺乏標準。
如今,所有標準都已完成或即將完成 ,這項新技術滿足了特定需求,并且在性能方面很有前途。 要大量使用該協議,將需要在通常僅允許HTTP協議的企業中使用該協議。
翻譯自: https://www.javacodegeeks.com/2014/01/java-ee-7-and-websocket-api-for-java-jsr-356-with-angularjs-on-wildfly.html
總結
以上是生活随笔為你收集整理的WildFly上具有AngularJS的Java EE 7和Java WebSocket API(JSR 356)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 955的含义 955解释
- 下一篇: 苹果屏幕旋转在哪关闭