A HttpServletRequest többszörös olvasása tavasszal
1. Bemutatkozás
Ebben az oktatóanyagban megtanuljuk, hogyan kell olvasni a testet a HttpServletRequest többször a Spring használatával.
HttpServletRequest egy olyan felület, amely leleplezi getInputStream () módszer a test leolvasására. Alapértelmezés szerint, az ebből származó adatok InputStream csak egyszer olvasható.
2. Maven-függőségek
Az első dolog, amire szükségünk lesz, az a megfelelő tavasz-webmvc és javax.servlet függőségek:
org.springframework spring-webmvc 5.2.0.RELEASE javax.servlet javax.servlet-api 4.0.1
Továbbá, mivel a alkalmazás / json tartalomtípus, az jackson-databind függőség szükséges:
com.fasterxml.jackson.core jackson-databind 2.10.0
A Spring ezt a könyvtárat használja a JSON-ba történő konvertáláshoz.
3. Tavaszi ContentCachingRequestWrapper
A tavasz biztosítja a ContentCachingRequestWrapper osztály. Ez az osztály egy módszert biztosít, getContentAsByteArray () hogy többször elolvassa a testet.
Ennek az osztálynak van korlátozása, bár: Nem olvashatjuk el többször a testet a getInputStream () és getReader () mód.
Ez az osztály gyorsítótárba helyezi a kéréstestet a InputStream. Ha elolvassuk a InputStream az egyik szűrőben, akkor a szűrő lánc többi következő szűrője már nem tudja olvasni. E korlátozás miatt ez az osztály nem alkalmas minden helyzetben.
Ennek a korlátnak a leküzdése érdekében most nézzünk meg egy általánosabb megoldást.
4. Hosszabbítás HttpServletRequest
Hozzunk létre egy új osztály - CachedBodyHttpServletRequest - amely kiterjed HttpServletRequestWrapper. Így nem kell felülírnunk a HttpServletRequest felület.
HttpServletRequestWrapper osztály két elvont módszerrel rendelkezik getInputStream () és getReader (). Mindkét módszert felülírjuk, és létrehozunk egy új konstruktort.
4.1. A kivitelező
Először hozzunk létre egy konstruktort. Belül leolvassuk a testet a ténylegesből InputStream és tárolja a byte[] tárgy:
public class CachedBodyHttpServletRequest kiterjeszti a HttpServletRequestWrapper {private byte [] cachedBody; public CachedBodyHttpServletRequest (HttpServletRequest kérés) dobja az IOException {super (kérés); InputStream requestInputStream = request.getInputStream (); this.cachedBody = StreamUtils.copyToByteArray (requestInputStream); }}
Ennek eredményeként többször is leolvashatjuk a testet.
4.2. getInputStream ()
Ezután írjuk felül a getInputStream () módszer. Ezt a módszert fogjuk használni a nyers törzs beolvasásához és objektummá alakításához.
Ebben a módszerben megtesszük hozzon létre és adjon vissza egy új objektumot CachedBodyServletInputStream osztály (a ServletInputStream):
@Orride public ServletInputStream getInputStream () dobja az IOException-t {return new CachedBodyServletInputStream (this.cachedBody); }
4.3. getReader ()
Akkor felülírjuk a getReader () módszer. Ez a módszer a BufferedReader tárgy:
@Orride public BufferedReader getReader () dobja az IOException {ByteArrayInputStream byteArrayInputStream = új ByteArrayInputStream (this.cachedBody); return new BufferedReader (új InputStreamReader (byteArrayInputStream)); }
5. Végrehajtása ServletInputStream
Hozzunk létre egy osztály - CachedBodyServletInputStream - amely megvalósítja ServletInputStream. Ebben az osztályban létrehozunk egy új konstruktort, és felülírjuk a befejeződött(), készen van() és olvas() mód.
5.1. A kivitelező
Először hozzunk létre egy új konstruktort, amely egy bájt tömböt vesz fel.
Belül létrehozunk egy új ByteArrayInputStream a bájt tömböt használva. Ezt követően hozzárendeljük a globális változóhoz cachedBodyInputStream:
public class CachedBodyServletInputStream kiterjeszti a ServletInputStream {private InputStream cachedBodyInputStream; public CachedBodyServletInputStream (byte [] cachedBody) {this.cachedBodyInputStream = új ByteArrayInputStream (cachedBody); }}
5.2. olvas()
Ezután felülírjuk a olvas() módszer. Ebben a módszerben felhívjuk ByteArrayInputStream # olvasása:
@Orride public int read () dob IOException {return cachedBodyInputStream.read (); }
5.3. befejeződött()
Ezután felülírjuk a befejeződött() módszer. Ez a módszer jelzi, hogy InputStream több adat van elolvasva vagy sem. Visszatér igaz amikor nulla bájt olvasható:
@Orride public boolean isFinished () {return cachedBody.available () == 0; }
5.4. készen van()
Hasonlóképpen felülírjuk a készen van() módszer. Ez a módszer jelzi, hogy InputStream készen áll az olvasásra, vagy sem.
Mivel már másoltuk InputStream egy bájtos tömbben visszatérünk igaz jelezni, hogy mindig elérhető:
@Orride public boolean isReady () {return true; }
6. A szűrő
Végül hozzunk létre egy új szűrőt a CachedBodyHttpServletRequest osztály. Itt kibővítjük a tavaszit OncePerRequestFilter osztály. Ennek az osztálynak van egy elvont módszere doFilterInternal ().
Ebben a módszerben megtesszük hozzon létre egy objektumot a CachedBodyHttpServletRequest osztály a tényleges kérelem objektumból:
CachedBodyHttpServletRequest cachedBodyHttpServletRequest = új CachedBodyHttpServletRequest (kérés);
Akkor majd adja át ezt az új kérésburkoló objektumot a szűrőláncnak. Tehát az összes következő hívás a getInputStream() metódus meghívja az felülbírált metódust:
filterChain.doFilter (cachedContentHttpServletRequest, válasz);
7. Következtetés
Ebben az oktatóanyagban gyorsan végigjártuk a ContentCachingRequestWrapper osztály. Láttuk a korlátait is.
Ezután létrehoztuk a HttpServletRequestWrapper osztály. Felülírtuk a getInputStream () metódus az objektum visszaküldéséhez ServletInputStream osztály.
Végül létrehoztunk egy új szűrőt, hogy továbbítsuk a kérésburkoló objektumot a szűrőlánchoz. Tehát többször elolvashattuk a kérést.
A példák teljes forráskódja megtalálható a GitHub oldalon.