Jersey szűrők és elfogók

1. Bemutatkozás

Ebben a cikkben elmagyarázzuk, hogyan működnek a szűrők és az elfogók a jersey-i keretrendszerben, valamint a fő különbségeket ezek között.

Itt a Jersey 2-t fogjuk használni, és Tomcat 9 szerver segítségével teszteljük alkalmazásunkat.

2. Az alkalmazás beállítása

Először hozzunk létre egy egyszerű erőforrást a szerverünkön:

@Path ("/ greetings") public class Greetings {@GET public String getHelloGreeting () {return "hello"; }}

Hozzuk létre továbbá a megfelelő kiszolgáló konfigurációt alkalmazásunkhoz:

A @ApplicationPath ("/ *") public class ServerConfig kiterjeszti a ResourceConfig {public ServerConfig () {csomagokat ("com.baeldung.jersey.server"); }}

Ha mélyebbre akarja találni, hogyan lehet API-t létrehozni Jersey-szel, akkor nézze meg ezt a cikket.

Ezenkívül megtekintheti az ügyfélközpontú cikkünket, és megtudhatja, hogyan lehet Java-ügyfelet létrehozni Jersey-vel.

3. Szűrők

Most kezdjük el a szűrőket.

Egyszerűen fogalmazva, A szűrők segítségével módosíthatjuk a kérések és válaszok tulajdonságait - például HTTP fejlécek. A szűrők a kiszolgáló és az ügyfél oldalán egyaránt alkalmazhatók.

Tartsd észben, hogy a szűrőket mindig végrehajtják, függetlenül attól, hogy az erőforrást megtalálták-e vagy sem.

3.1. Kérés-kiszolgáló szűrő megvalósítása

Kezdjük a kiszolgáló oldali szűrőkkel, és hozzunk létre egy kérés szűrőt.

Megtesszük ezt a ContainerRequestFilter interfész és regisztráció a Szolgáltató a szerverünkön:

A @Provider public class RestrictedOperationsRequestFilter megvalósítja a ContainerRequestFilter {@Orride public void filter (ContainerRequestContext ctx) dobja az IOException {if (ctx.getLanguage ()! = Null && "EN" .equals (ctx.getLgetuang) ( .abortWith (Response.status (Response.Status.FORBIDDEN) .entity ("Nem lehet elérni" .build ()); }}}

Ez az egyszerű szűrő csak elutasítja a kéréseket a nyelvvel „EN” a kérésben a abortWith () módszer.

Mint a példa mutatja, csak egy módszert kellett végrehajtanunk, amely megkapja a kérés kontextusát, amelyet szükség szerint módosíthatunk.

Ezt tartsuk szem előtt ez a szűrő az erőforrás egyeztetése után kerül végrehajtásra.

Ha az erőforrás-egyeztetés előtt szűrőt akarunk végrehajtani, használhatunk egy előre illesztett szűrőt, ha a szűrőnkkel jelöljük a @PreMatching annotáció:

@Provider @PreMatching public class PrematchingRequestFilter megvalósítja a ContainerRequestFilter {@Override public void filter (ContainerRequestContext ctx) dobja az IOException {if (ctx.getMethod (). Egyenlő ("DELETE")) {LOG "Deleto" kérés }}}

Ha most megpróbálunk hozzáférni az erőforrásunkhoz, akkor ellenőrizhetjük, hogy az előillesztési szűrőnk először lett-e végrehajtva:

2018-02-25 16: 07: 27,800 [http-nio-8080-exec-3] INFO cbjsfPrematchingRequestFilter - előcsatlakozó szűrő 2018-02-25 16: 07: 27,816 [http-nio-8080-exec-3] INFO cbjsf RestrictedOperationsRequestFilter - Korlátozott műveletek szűrője

3.2. Válaszkiszolgáló szűrő megvalósítása

Most a szerver oldalon megvalósítunk egy válaszszűrőt, amely csupán új fejlécet ad a válaszhoz.

Ehhez, szűrőnknek végre kell hajtania a ContainerResponseFilter felület és alkalmazza egyetlen módszerét:

A @Provider public class ResponseServerFilter végrehajtja a ContainerResponseFilter {@Orride public void filter (ContainerRequestContext requestContext, ContainerResponseContext responseContext) dobja az IOException {responseContext.getHeaders (). Add ("X-Test", "Filter" }}

Figyeljük meg, hogy a ContainerRequestContext paramétert csak olvashatóként használják - mivel már feldolgozzuk a választ.

2.3. Ügyfélszűrő megvalósítása

Most az ügyféloldali szűrőkkel fogunk dolgozni. Ezek a szűrők ugyanúgy működnek, mint a szerverszűrők, és az általunk megvalósítandó interfészek nagyon hasonlítanak a kiszolgálói oldalra.

Lássuk működés közben egy szűrővel, amely tulajdonságot ad hozzá a kéréshez:

A @Provider public class RequestClientFilter megvalósítja a ClientRequestFilter {@Orride public void filter (ClientRequestContext requestContext) dobja az IOException {requestContext.setProperty ("teszt", "teszt kliens kérés szűrő"); }}

Hozzunk létre egy Jersey-ügyfelet is a szűrő teszteléséhez:

nyilvános osztály JerseyClient {private static String URI_GREETINGS = "// localhost: 8080 / jersey / greetings"; public static String getHelloGreeting () {return createClient (). target (URI_GREETINGS) .request () .get (String.class); } privát statikus Client createClient () {ClientConfig config = new ClientConfig (); config.register (RequestClientFilter.class); return ClientBuilder.newClient (config); }}

Figyelje meg, hogy hozzá kell adnunk a szűrőt az ügyfélkonfigurációhoz a regisztrációhoz.

Végül létrehozunk egy szűrőt a kliens válaszára is.

Ez nagyon hasonló módon működik, mint a szerveren, de a ClientResponseFilter felület:

A @Provider public class ResponseClientFilter implementálja a ClientResponseFilter {@Orride public void filter (ClientRequestContext requestContext, ClientResponseContext responseContext) dobja az IOException {responseContext.getHeaders () .add ("X-Test-Client"; "Teszt válasz ügyfélszűrő"; }}

Ismét a ClientRequestContext csak olvasható célokra szolgál.

4. Elfogók

Az elfogók jobban kapcsolódnak a kérésekben és válaszokban szereplő HTTP üzenettestek rendezéséhez és feloldásához. A kiszolgálón és az ügyfél oldalon egyaránt használhatók.

Tartsd észben, hogy a szűrők után hajtják végre őket, és csak akkor, ha egy üzenet törzs van jelen.

Kétféle elfogó van: ReaderInterceptor és WriterInterceptor, és mind a szerver, mind az ügyfél oldalon megegyeznek.

Ezután létrehozunk egy másik erőforrást a szerverünkön, amelyhez a POST-on keresztül férhet hozzá, és egy paramétert fogad a testben, így az elfogók végrehajtásra kerülnek, amikor elérik:

@POST @Path ("/ custom") public Response getCustomGreeting (String name) {return Response.status (Status.OK.getStatusCode ()) .build (); }

Ezenkívül hozzáadunk egy új módszert Jersey ügyfelünkhöz - ennek az új erőforrásnak a teszteléséhez:

public static Response getCustomGreeting () {return createClient (). target (URI_GREETINGS + "/ custom") .request () .post (Entity.text ("custom")); }

4.1. Megvalósítása a ReaderInterceptor

Az olvasók elfogói lehetővé teszik a bejövő adatfolyamok manipulálását, így felhasználhatjuk őket a szerver oldali kérés vagy az ügyfél oldali válasz módosítására.

Hozzunk létre egy elfogót a kiszolgáló oldalán, hogy egyéni üzenetet írjunk az elfogott kérelem törzsébe:

A @Provider public class RequestServerReaderInterceptor megvalósítja a ReaderInterceptor {@Orride public Object aroundReadFrom (ReaderInterceptorContext context) dobja az IOException, WebApplicationException {InputStream is = context.getInputStream (); Karaktersorozat = new BufferedReader (new InputStreamReader (is)). Sorok () .collect (Collectors.joining ("\ n")); context.setInputStream (új ByteArrayInputStream ((body + "üzenet hozzáadva a szerverolvasó elfogóhoz"). getBytes ())); return context.proceed (); }}

Figyelje meg hívnunk kell a folytassa() módszerhogy felhívja a következő elfogót a láncban. Miután az összes elfogót végrehajtották, a megfelelő üzenettörzs-olvasót hívják meg.

3.2. Megvalósítása a WriterInterceptor

Az író elfogók az olvasó elfogókhoz hasonlóan működnek, de manipulálják a kimenő adatfolyamokat - hogy felhasználhassuk őket az ügyféloldali kéréssel vagy a szerveroldali válaszsal.

Hozzunk létre egy író elfogót, hogy üzenetet adjon a kéréshez, az ügyfél oldalon:

@Provider public class RequestClientWriterInterceptor implementálja a WriterInterceptor {@Orride public void aroundWriteTo (WriterInterceptorContext context) dobja az IOException, WebApplicationException {context.getOutputStream () context.proceed (); }}

Ismét meg kell hívnunk a módszert folytassa() hogy felhívja a következő elfogót.

Amikor az összes elfogót végrehajtják, a megfelelő üzenettörzs írót hívják meg.

Ne felejtse el, hogy ezt az elfogót regisztrálnia kell az ügyfél konfigurációjában, ahogy korábban az ügyfélszűrővel tettük:

privát statikus Client createClient () {ClientConfig config = new ClientConfig (); config.register (RequestClientFilter.class); config.register (RequestWriterInterceptor.class); return ClientBuilder.newClient (config); }

5. Végrehajtási parancs

Összegezzük mindazt, amit eddig láttunk, egy diagramban, amely megmutatja, hogy a szűrőket és az elfogókat mikor hajtják végre egy kliens és egy szerver közötti kérés során:

Ahogy látjuk, a szűrőket mindig először hajtják végre, és az elfogókat közvetlenül a megfelelő üzenettörzs-olvasó vagy író felhívása előtt hajtják végre.

Ha megnézzük az általunk létrehozott szűrőket és elfogókat, akkor a következő sorrendben kerülnek végrehajtásra:

  1. RequestClientFilter
  2. RequestClientWriterInterceptor
  3. PrematchingRequestFilter
  4. RestrictedOperationsRequestFilter
  5. RequestServerReaderInterceptor
  6. ResponseServerFilter
  7. ResponseClientFilter

Továbbá, ha több szűrőnk vagy elfogónk van, megadhatjuk a pontos végrehajtási sorrendet azáltal, hogy azokat a @Kiemelten fontos annotáció.

A prioritást egy gombbal adjuk meg Egész szám és a szűrőket és az elfogókat növekvő sorrendben rendezi a kérések és a válaszok csökkenő sorrendjében.

Vegyünk egy prioritást a mi RestrictedOperationsRequestFilter:

@Provider @Priority (Priorities.AUTHORIZATION) public class RestrictedOperationsRequestFilter implementálja a ContainerRequestFilter {// ...}

Vegye figyelembe, hogy engedélyezés céljából előre meghatározott prioritást használtunk.

6. Névkötés

Az eddig látott szűrőket és elfogókat globálisnak nevezzük, mivel minden kérésre és válaszra végrehajtják őket.

Azonban, úgy is meghatározhatók, hogy csak meghatározott erőforrás-módszerek esetén hajthatók végre, amelyet névkötésnek hívnak.

6.1. Statikus kötés

A név-összerendelés egyik módja statikusan egy adott kommentár létrehozásával, amelyet a kívánt erőforrásban fognak használni. Ennek a feljegyzésnek tartalmaznia kell a @NévKötés meta-annotáció.

Hozzunk létre egyet az alkalmazásunkban:

@NameBinding @Retention (RetentionPolicy.RUNTIME) public @interface HelloBinding {}

Ezt követően néhány erőforrást feljegyezhetünk ezzel @HelloBinding kommentár:

@GET @HelloBinding public String getHelloGreeting () {return "hello"; }

Végül az egyik szűrőnket ezzel a feljegyzéssel is jegyezzük, így ez a szűrő csak azokra a kérésekre és válaszokra kerül végrehajtásra, amelyek hozzáférnek a getHelloGreeting () módszer:

@Provider @Priority (Priorities.AUTHORIZATION) @HelloBinding public class RestrictedOperationsRequestFilter implementálja a ContainerRequestFilter {// ...}

Ne feledje, hogy a mi RestrictedOperationsRequestFilter az erőforrások többi részénél már nem aktiválódik.

6.2. Dinamikus kötés

Ennek másik módja egy dinamikus kötés használata, amelyet az indításkor a konfigurációba töltünk be.

Először adjunk hozzá egy másik erőforrást a szerverünkhöz ehhez a szakaszhoz:

@GET @Path ("/ hi") public String getHiGreeting () {return "szia"; }

Most hozzunk létre egy kötést ehhez az erőforráshoz a DynamicFeature felület:

A @Provider public class HelloDynamicBinding megvalósítja a DynamicFeature {@Override public void configure (ResourceInfo resourceInfo, FeatureContext context) {if (Üdvözlet.class.equals (resourceInfo.getResourceClass ()) && resourceInfo.getResourceMethod () getName () ")) {context.register (ResponseServerFilter.class); }}}

Ebben az esetben társítjuk a getHiGreeting () módszer a ResponseServerFilter amit korábban létrehoztunk.

Fontos megjegyezni, hogy törölnünk kellett a @ Szolgáltató kommentár ettől a szűrőtől, mivel mostantól konfiguráljuk DynamicFeature.

Ha ezt nem tesszük meg, akkor a szűrő kétszer lesz végrehajtva: egy alkalommal globális szűrőként, máskor pedig a getHiGreeting () módszer.

7. Következtetés

Ebben az oktatóanyagban arra összpontosítottunk, hogy megértsük, hogyan működnek a szűrők és az elfogók Jersey 2-ben, és hogyan használhatjuk őket egy webalkalmazásban.

Mint mindig, a példák teljes forráskódja elérhető a GitHubon.