Sprievodca Java API pre WebSocket

1. Prehľad

WebSocket poskytuje alternatívu k obmedzeniu efektívnej komunikácie medzi serverom a webovým prehliadačom poskytovaním obojsmernej, plne duplexnej komunikácie medzi klientom a serverom v reálnom čase. Server môže klientovi kedykoľvek odoslať údaje. Pretože beží cez TCP, poskytuje aj nízkolatenčnú komunikáciu na nízkej úrovni a znižuje réžiu každej správy.

V tomto článku sa pozrieme na Java API pre WebSockets vytvorením aplikácie podobnej chatu.

2. JSR 356

JSR 356 alebo Java API pre WebSocket špecifikuje API, ktoré môžu vývojári Java použiť na integráciu WebSocketov do svojich aplikácií - na strane servera aj na strane klienta Java.

Toto rozhranie Java API poskytuje komponenty na strane servera aj klienta:

  • Server: všetko v javax.websocket.server balíček.
  • Zákazník: obsah javax.websocket balík, ktorý sa skladá z API na strane klienta a tiež zo spoločných knižníc pre server aj klienta.

3. Budovanie chatu pomocou webových zásuviek

Postavíme veľmi jednoduchú aplikáciu podobnú chatu. Každý užívateľ bude môcť otvoriť chat z ľubovoľného prehľadávača, zadať jeho meno, prihlásiť sa do chatu a začať komunikovať so všetkými pripojenými k chatu.

Začneme pridaním najnovšej závislosti do pom.xml spis:

 javax.websocket javax.websocket-api 1.1 

Najnovšiu verziu nájdete tu.

Za účelom prevodu Java Predmety do ich reprezentácií JSON a naopak, použijeme Gson:

 com.google.code.gson gson 2.8.0 

Najnovšia verzia je k dispozícii v úložisku Maven Central.

3.1. Konfigurácia koncového bodu

Existujú dva spôsoby konfigurácie koncových bodov: anotácia-založené na rozšírení. Môžete buď predĺžiť javax.websocket.Endpoint triedy alebo použiť vyhradené anotácie na úrovni metódy. Pretože anotačný model vedie k čistejšiemu kódu v porovnaní s programovým modelom, stala sa anotácia konvenčnou voľbou kódovania. V takom prípade sú udalosti životného cyklu koncového bodu WebSocket spracované nasledujúcimi anotáciami:

  • @ServerEndpoint: Ak je zdobené @ServerEndpoint, kontajner zaisťuje dostupnosť triedy ako a WebSocket server počúvajúci konkrétny priestor URI
  • @ClientEndpoint: S triedou zdobenou touto anotáciou sa zaobchádza ako s WebSocket zákazník
  • @OnOpen: Metóda Java s @OnOpen je vyvolaný kontajnerom, keď je nový WebSocket pripojenie sa inicializuje
  • @OnMessage: Metóda Java s poznámkami @OnMessage, prijíma informácie od WebSocket kontajner pri odoslaní správy do koncového bodu
  • @OnError: Metóda s @OnError sa vyvolá, ak sa vyskytol problém s komunikáciou
  • @OnClose: Používa sa na ozdobenie metódy Java, ktorá sa volá kontajnerom, keď WebSocket spojenie sa uzatvára

3.2. Zápis koncového bodu servera

Deklarujeme triedu Java WebSocket koncový bod servera tým, že ho anotuje pomocou @ServerEndpoint. Tiež zadáme URI, kde je nasadený koncový bod. URI je definovaný relatívne ku koreňu kontajnera servera a musí začínať lomkou:

@ServerEndpoint (value = "/ chat / {username}") verejná trieda ChatEndpoint {@OnOpen public void onOpen (relácia relácie) vyvolá IOException {// Get session and WebSocket connection} @OnMessage public void onMessage (relácia relácie, správa správy) vyvolá IOException {// Spracovanie nových správ} @OnClose public void onClose (relácia relácie) vyvolá IOException {// pripojenie WebSocket sa ukončí} @OnError verejné void onError (relácia relácie, hoditeľná) {// Vykonajte spracovanie chýb tu}}

Vyššie uvedený kód je kostrou koncového bodu servera pre našu aplikáciu podobnú chatu. Ako vidíte, máme 4 anotácie mapované k ich príslušným metódam. Ďalej vidíte implementáciu týchto metód:

@ServerEndpoint (value = "/ chat / {username}") verejná trieda ChatEndpoint {relácia súkromnej relácie; private static Set chatEndpoints = new CopyOnWriteArraySet (); súkromní statickí používatelia HashMap = nový HashMap (); @OnOpen public void onOpen (relácia relácie, @PathParam ("používateľské meno") reťazec používateľské meno) vyvolá výnimku IOException {this.session = session; chatEndpoints.add (toto); users.put (session.getId (), meno používateľa); Správa správy = nová správa (); message.setFrom (meno používateľa); message.setContent ("Pripojené!"); vysielanie (správa); } @OnMessage public void onMessage (relácia relácie, správa správy) hodí IOException {message.setFrom (users.get (session.getId ())); vysielanie (správa); } @OnClose public void onClose (relácia relácie) vyvolá IOException {chatEndpoints.remove (this); Správa správy = nová správa (); message.setFrom (users.get (session.getId ())); message.setContent ("Odpojené!"); vysielanie (správa); } @OnError public void onError (Session session, Throwable throwable) {// Robiť chyby tu}} súkromné ​​static void broadcast (správa správy) hodí IOException, EncodeException {chatEndpoints.forEach (endpoint -> {synchronized (endpoint) {try {endpoint) .session.getBasicRemote (). sendObject (správa);} chytiť (IOException | EncodeException e) {e.printStackTrace ();}}}); }}

Keď sa nový používateľ prihlási (@OnOpen) je okamžite namapovaný na dátovú štruktúru aktívnych používateľov. Potom sa vytvorí správa a odošle sa na všetky koncové body pomocou vysielať metóda.

Táto metóda sa používa aj pri každom odoslaní novej správy (@OnMessage) ktorýmkoľvek z pripojených používateľov - to je hlavný účel chatu.

Ak v určitom okamihu dôjde k chybe, použije sa metóda s anotáciou @OnError zvláda to. Touto metódou môžete zaznamenať informácie o chybe a vyčistiť koncové body.

Nakoniec, keď už používateľ nie je pripojený k chatu, postup @OnClose vymaže koncový bod a vysiela všetkým používateľom, že používateľ bol odpojený.

4. Typy správ

Špecifikácia WebSocket podporuje dva on-wire dátové formáty - textový a binárny. API podporuje oba tieto formáty, pridáva možnosti práce s objektmi Java a správami o kontrole stavu (ping-pong), ako sú definované v špecifikácii:

  • Text: Akékoľvek textové údaje (java.lang.String, primitívne látky alebo ich ekvivalentné triedy obalov)
  • Binárne: Binárne údaje (napr. Zvuk, obraz atď.) Predstavované a java.nio.ByteBuffer alebo a byte [] (bajtové pole)
  • Java objekty: API umožňuje vo vašom kóde pracovať s natívnymi (objektmi Java) reprezentáciami a používať vlastné transformátory (kódovače / dekodéry) na ich konverziu do kompatibilných formátov on-wire (textových, binárnych) povolených protokolom WebSocket.
  • Stolný tenis: A javax.websocket.PongMessage je potvrdenie odoslané kolegom WebSocket v reakcii na požiadavku na kontrolu stavu (ping)

Pre našu aplikáciu budeme používať Objekty Java. Vytvoríme triedy na kódovanie a dekódovanie správ.

4.1. Kódovač

Kodér vezme objekt Java a vytvorí typickú reprezentáciu vhodnú na prenos ako správu, ako je JSON, XML alebo binárna reprezentácia. Kodéry je možné použiť implementáciou Encoder.Text alebo Kodér. Binárne rozhrania.

V kóde nižšie definujeme triedu Správa byť zakódovaný a v metóde zakódovať používame Gson na kódovanie objektu Java do formátu JSON:

public class Správa {private String from; private String to; súkromný obsah reťazca; // štandardné konštruktory, getre, setre}
verejná trieda MessageEncoder implementuje Encoder.Text {private static Gson gson = new Gson (); @ Verzia public String encode (správa správy) vyvolá EncodeException {return gson.toJson (správa); } @Override public void init (EndpointConfig endpointConfig) {// Logika vlastnej inicializácie} @Override public void zničiť () {// Zatvoriť zdroje}}

4.2. Dekodér

Dekodér je opakom kódovacieho zariadenia a používa sa na transformáciu údajov späť do objektu Java. Dekodéry je možné implementovať pomocou Dekodér. Text alebo Dekodér. Binárne rozhrania.

Ako sme videli u kódovacieho zariadenia, dekódovať metóda je taká, kde vezmeme JSON načítaný v správe odoslanej do koncového bodu a pomocou Gsonu ho transformujeme na triedu Java s názvom Správa:

verejná trieda MessageDecoder implementuje Decoder.Text {private static Gson gson = new Gson (); @Override public decode správy (String s) hodí DecodeException {return gson.fromJson (s, Message.class); } @Override public boolean willDecode (String s) {return (s! = Null); } @Override public void init (EndpointConfig endpointConfig) {// Logika vlastnej inicializácie} @Override public void zničiť () {// Zatvoriť zdroje}}

4.3. Nastavenie kodéra a dekodéra v koncovom bode servera

Poďme všetko spojiť pridaním tried vytvorených na kódovanie a dekódovanie údajov na anotácii na úrovni triedy @ServerEndpoint:

@ServerEndpoint (value = "/ chat / {username}", dekodéry = MessageDecoder.class, encoders = MessageEncoder.class)

Zakaždým, keď sa správy odosielajú do koncového bodu, automaticky sa prevedú na objekty JSON alebo Java.

5. Záver

V tomto článku sme sa pozreli na to, čo je Java API pre WebSockets a ako nám môže pomôcť pri vytváraní aplikácií, ako je tento chat v reálnom čase.

Videli sme dva programovacie modely na vytvorenie koncového bodu: anotácie a programové. Definovali sme koncový bod pomocou anotačného modelu pre našu aplikáciu spolu s metódami životného cyklu.

Aby sme mohli komunikovať medzi serverom a klientom, zistili sme, že na prevod objektov Java na formát JSON a naopak potrebujeme kodéry a dekodéry.

API JSR 356 je veľmi jednoduché a programovací model založený na anotáciách, ktorý umožňuje veľmi ľahko vytvárať aplikácie WebSocket.

Aby sme mohli spustiť aplikáciu, ktorú sme vytvorili v príklade, musíme iba nasadiť vojnový súbor na webový server a prejsť na adresu URL: // localhost: 8080 / java-websocket /. Odkaz na úložisko nájdete tu.