En guide til Java API til WebSocket

1. Oversigt

WebSocket giver et alternativ til begrænsningen af ​​effektiv kommunikation mellem serveren og webbrowseren ved at levere tovejs, fuld duplex, klient / server-kommunikation i realtid. Serveren kan til enhver tid sende data til klienten. Fordi det kører over TCP, giver det også en kommunikation på lavt niveau med lav latens og reducerer omkostningerne ved hver besked.

I denne artikel ser vi på Java API for WebSockets ved at oprette en chatlignende applikation.

2. JSR 356

JSR 356 eller Java API til WebSocket angiver en API, som Java-udviklere kan bruge til at integrere WebSockets med deres applikationer - både på serversiden såvel som på Java-klientsiden.

Denne Java API giver både server- og klientsidekomponenter:

  • Server: alt i javax.websocket.server pakke.
  • Klient: indholdet af javax.websocket pakke, som består af klientsides-API'er og også almindelige biblioteker til både server og klient.

3. Opbygning af en chat ved hjælp af WebSockets

Vi bygger en meget enkel chatlignende applikation. Enhver bruger vil være i stand til at åbne chatten fra enhver browser, skrive sit navn, logge ind i chatten og begynde at kommunikere med alle, der er forbundet til chatten.

Vi starter med at tilføje den seneste afhængighed af pom.xml fil:

 javax.websocket javax.websocket-api 1.1 

Den seneste version kan findes her.

For at konvertere Java Objekter i deres JSON-repræsentationer og omvendt bruger vi Gson:

 com.google.code.gson gson 2.8.0 

Den seneste version er tilgængelig i Maven Central repository.

3.1. Slutpunktskonfiguration

Der er to måder at konfigurere slutpunkter på: kommentar-baseret og udvidelsesbaseret. Du kan enten udvide javax.websocket.Endpoint klasse eller bruge dedikerede annoteringer på metodeniveau. Da annotationsmodellen fører til renere kode sammenlignet med den programmatiske model, er annotationen blevet det konventionelle valg af kodning. I dette tilfælde håndteres WebSocket-slutpunkts livscyklushændelser af følgende kommentarer:

  • @ ServerEndpoint: Hvis dekoreret med @ServerEndpoint, containeren sikrer tilgængelighed af klassen som en WebSocket server, der lytter til et specifikt URI-rum
  • @ClientEndpoint: En klasse dekoreret med denne kommentar behandles som en WebSocket klient
  • @OnOpen: En Java-metode med @OnOpen påberåbes af containeren, når en ny WebSocket forbindelsen er startet
  • @OnMessage: En Java-metode, kommenteret med @OnMessage, modtager oplysningerne fra WebSocket container, når en besked sendes til slutpunktet
  • @OnError: En metode med @OnError påberåbes, når der er et problem med kommunikationen
  • @OnClose: Bruges til at dekorere en Java-metode, der kaldes af containeren, når WebSocket forbindelsen lukkes

3.2. Skrivning af serverendepunkt

Vi erklærer en Java-klasse WebSocket serverendepunkt ved at kommentere det med @ ServerEndpoint. Vi specificerer også URI, hvor slutpunktet er implementeret. URI er defineret relativt til roden af ​​servercontaineren og skal begynde med en skråstreg:

@ ServerEndpoint (værdi = "/ chat / {brugernavn}") offentlig klasse ChatEndpoint {@OnOpen offentlig ugyldighed onOpen (session session) kaster IOException {// Få session og WebSocket forbindelse} @OnMessage offentlig ugyldig onMessage (session session, besked besked) kaster IOException {// Håndter nye meddelelser} @OnClose public void onClose (Session session) kaster IOException {// WebSocket-forbindelse lukkes} @OnError public void onError (Session session, Throwable throwable) {// Gør fejlhåndtering her}}

Koden ovenfor er serverens slutpunktskelett til vores chatlignende applikation. Som du kan se, har vi 4 annoteringer kortlagt til deres respektive metoder. Nedenfor kan du se implementeringen af ​​sådanne metoder:

@ServerEndpoint (værdi = "/ chat / {brugernavn}") offentlig klasse ChatEndpoint {privat session session; privat statisk Sæt chatEndpoints = ny CopyOnWriteArraySet (); private statiske HashMap-brugere = nye HashMap (); @OnOpen offentligt ugyldigt onOpen (session session, @PathParam ("brugernavn") streng brugernavn) kaster IOException {this.session = session; chatEndpoints.add (dette); users.put (session.getId (), brugernavn); Beskedbesked = ny besked (); message.setFrom (brugernavn); message.setContent ("Forbundet!"); udsendelse (besked); } @OnMessage offentlig ugyldighed onMessage (session session, besked besked) kaster IOException {message.setFrom (users.get (session.getId ())); udsendelse (besked); } @OnClose offentlig ugyldighed onClose (session session) kaster IOException {chatEndpoints.remove (dette); Beskedbesked = ny besked (); message.setFrom (brugere.get (session.getId ())); message.setContent ("Afbrudt!"); udsendelse (besked); } @OnError public void onError (Session session, Throwable throwable) {// Do error handling here} private static void broadcast (Message message) throw IOException, EncodeException {chatEndpoints.forEach (endpoint -> {synchronized (endpoint) {try {endpoint .session.getBasicRemote (). sendObject (meddelelse);} fangst (IOException | EncodeException e) {e.printStackTrace ();}}}); }}

Når en ny bruger logger på (@OnOpen) kortlægges straks til en datastruktur for aktive brugere. Derefter oprettes en besked og sendes til alle slutpunkter ved hjælp af udsende metode.

Denne metode bruges også, når der sendes en ny besked (@OnMessage) af nogen af ​​de forbundne brugere - dette er det vigtigste formål med chatten.

Hvis der på et tidspunkt opstår en fejl, er metoden med kommentaren @OnError håndterer det. Du kan bruge denne metode til at logge oplysningerne om fejlen og rydde slutpunkterne.

Endelig, når en bruger ikke længere er forbundet til chatten, metoden @OnClose rydder slutpunktet og udsender til alle brugere, at en bruger er blevet afbrudt.

4. Beskedtyper

WebSocket-specifikationen understøtter to on-wire dataformater - tekst og binær. API'en understøtter begge disse formater, tilføjer muligheder for at arbejde med Java-objekter og sundhedstjekbeskeder (ping-pong) som defineret i specifikationen:

  • Tekst: Eventuelle tekstdata (java.lang.Strengprimitiver eller tilsvarende indpakningsklasser)
  • Binær: Binære data (f.eks. Lyd, billede osv.) Repræsenteret af en java.nio.ByteBuffer eller a byte [] (byte array)
  • Java-objekter: API'en gør det muligt at arbejde med native (Java-objekt) -repræsentationer i din kode og bruge brugerdefinerede transformatorer (kodere / dekodere) til at konvertere dem til kompatible on-wire-formater (tekst, binær) tilladt af WebSocket-protokollen
  • Bordtennis: A javax.websocket.PongMessage er en bekræftelse, der sendes af en WebSocket-peer som svar på en anmodning om sundhedstjek (ping)

Til vores ansøgning bruger vi Java-objekter. Vi opretter klasser til kodning og afkodning af meddelelser.

4.1. Koder

En indkoder tager et Java-objekt og producerer en typisk repræsentation, der er egnet til transmission som en besked, såsom JSON, XML eller binær repræsentation. Kodere kan bruges ved at implementere Encoder.Text eller Koder. Binær grænseflader.

I nedenstående kode definerer vi klassen Besked skal kodes og i metoden kode vi bruger Gson til kodning af Java-objektet til JSON:

offentlig klassemeddelelse {privat streng fra; privat streng til; privat strengindhold; // standard konstruktører, getters, setters}
offentlig klasse MessageEncoder implementerer Encoder.Text {privat statisk Gson gson = ny Gson (); @ Override public Strengkode (Beskedbesked) kaster EncodeException {return gson.toJson (besked); } @Override public void init (EndpointConfig endpointConfig) {// Tilpasset initialiseringslogik} @Override public void destroy () {// Luk ressourcer}}

4.2. Dekoder

En dekoder er det modsatte af en indkoder og bruges til at omdanne data tilbage til et Java-objekt. Dekodere kan implementeres ved hjælp af Dekoder Tekst eller Dekoder. Binær grænseflader.

Som vi så med koderen, blev afkode metode er hvor vi tager JSON hentet i meddelelsen sendt til slutpunktet og bruger Gson til at omdanne den til en Java-klasse kaldet Besked:

offentlig klasse MessageDecoder implementerer Decoder.Text {privat statisk Gson gson = ny Gson (); @Override public Message decode (String s) throw DecodeException {return gson.fromJson (s, Message.class); } @Override public boolean willDecode (String s) {return (s! = Null); } @Override public void init (EndpointConfig endpointConfig) {// Tilpasset initialiseringslogik} @Override public void destroy () {// Luk ressourcer}}

4.3. Indstilling af koder og dekoder i serverens slutpunkt

Lad os sætte alt sammen ved at tilføje de klasser, der er oprettet til kodning og afkodning af dataene på klassens niveau-kommentar @ ServerEndpoint:

@ ServerEndpoint (værdi = "/ chat / {brugernavn}", dekodere = MessageDecoder.class, encoders = MessageEncoder.class)

Hver gang beskeder sendes til slutpunktet, konverteres de automatisk enten til JSON- eller Java-objekter.

5. Konklusion

I denne artikel så vi på, hvad der er Java API til WebSockets, og hvordan det kan hjælpe os med at opbygge applikationer som denne realtidschat.

Vi så de to programmeringsmodeller til oprettelse af et slutpunkt: annoteringer og programmatiske. Vi definerede et slutpunkt ved hjælp af annoteringsmodellen til vores anvendelse sammen med livscyklusmetoderne.

For at kunne kommunikere frem og tilbage mellem serveren og klienten så vi også, at vi har brug for kodere og dekodere for at konvertere Java-objekter til JSON og omvendt.

JSR 356 API er meget enkel og den annoteringsbaserede programmeringsmodel, der gør det meget nemt at opbygge WebSocket-applikationer.

For at køre den applikation, vi byggede i eksemplet, er alt, hvad vi skal gøre, at implementere krigsfilen på en webserver og gå til URL: // localhost: 8080 / java-websocket /. Du kan finde linket til arkivet her.