Čítanie HttpServletRequest viackrát na jar

1. Úvod

V tomto tutoriále sa naučíme, ako čítať telo z HttpServletRequest viackrát pomocou jari.

HttpServletRequest je rozhranie, ktoré vystavuje getInputStream () metóda na čítanie tela. Predvolene, údaje z toho InputStream je možné prečítať iba raz.

2. Maven závislosti

Prvá vec, ktorú budeme potrebovať, je vhodná jar-webmvc a javax.servlet závislosti:

 org.springframework spring-webmvc 5.2.0.RELEASE javax.servlet javax.servlet-api 4.0.1 

Tiež, pretože používame aplikácia / json typ obsahu, jackson-databind je vyžadovaná závislosť:

 com.fasterxml.jackson.core jackson-databind 2.10.0 

Spring používa túto knižnicu na prevod do a zo formátu JSON.

3. Jarné ContentCachingRequestWrapper

Jar poskytuje a ContentCachingRequestWrapper trieda. Táto trieda poskytuje metódu, getContentAsByteArray () čítať telo viackrát.

Táto trieda má však svoje obmedzenia: Telo nedokážeme prečítať viackrát pomocou getInputStream () a getReader () metódy.

Táto trieda ukladá do pamäti telo žiadosti tým, že spotrebúva InputStream. Keby sme si prečítali InputStream v jednom z filtrov, ďalšie ďalšie filtre v reťazci filtrov ho už nemôžu prečítať. Z tohto dôvodu nie je táto trieda vhodná vo všetkých situáciách.

Aby sme prekonali toto obmedzenie, poďme sa teraz pozrieť na všeobecnejšie riešenie.

4. Predĺženie HttpServletRequest

Vytvorme a nová trieda - CachedBodyHttpServletRequest - ktorý sa rozširuje HttpServletRequestWrapper. Týmto spôsobom nemusíme prepísať všetky abstraktné metódy protokolu HttpServletRequest rozhranie.

HttpServletRequestWrapper trieda má dve abstraktné metódy getInputStream () a getReader (). Obe tieto metódy prepíšeme a vytvoríme nového konštruktora.

4.1. Konštruktér

Najskôr vytvorme konštruktor. V jeho vnútri budeme čítať telo od skutočného InputStream a uložte do a byte [] objekt:

public class CachedBodyHttpServletRequest rozširuje HttpServletRequestWrapper {private byte [] cachedBody; public CachedBodyHttpServletRequest (požiadavka HttpServletRequest) hodí IOException {super (požiadavka); InputStream requestInputStream = request.getInputStream (); this.cachedBody = StreamUtils.copyToByteArray (requestInputStream); }}

Vďaka tomu budeme môcť telo prečítať viackrát.

4.2. getInputStream ()

Ďalej prepíšeme getInputStream () metóda. Túto metódu použijeme na načítanie nespracovaného tela a jeho prevedenie na objekt.

V tejto metóde budeme vytvoriť a vrátiť nový objekt CachedBodyServletInputStream trieda (implementácia ServletInputStream):

@Override public ServletInputStream getInputStream () vyvolá IOException {return new CachedBodyServletInputStream (this.cachedBody); }

4.3. getReader ()

Potom prepíšeme getReader () metóda. Táto metóda vracia a BufferedReader objekt:

@Override public BufferedReader getReader () hodí IOException {ByteArrayInputStream byteArrayInputStream = nový ByteArrayInputStream (this.cachedBody); vrátiť nový BufferedReader (nový InputStreamReader (byteArrayInputStream)); }

5. Implementácia ServletInputStream

Vytvorme a trieda - CachedBodyServletInputStream - ktorý bude realizovať ServletInputStream. V tejto triede vytvoríme nový konštruktor a prepíšeme je dokončené(), je hotový() a čítať() metódy.

5.1. Konštruktér

Najskôr vytvorme nový konštruktor, ktorý prevezme bajtové pole.

V jeho vnútri vytvoríme Nový ByteArrayInputStream napríklad pomocou tohto bajtového poľa. Potom to priradíme ku globálnej premennej cachedBodyInputStream:

verejná trieda CachedBodyServletInputStream rozširuje ServletInputStream {private InputStream cachedBodyInputStream; public CachedBodyServletInputStream (byte [] cachedBody) {this.cachedBodyInputStream = nový ByteArrayInputStream (cachedBody); }}

5.2. čítať()

Potom prepíšeme čítať() metóda. V tejto metóde zavoláme ByteArrayInputStream # prečítané:

@Override public int read () hodí IOException {return cachedBodyInputStream.read (); }

5.3. je dokončené()

Potom prepíšeme je dokončené() metóda. Táto metóda naznačuje, či InputStream má viac údajov na čítanie alebo nie. Vracia sa to pravda keď je k dispozícii na čítanie nula bajtov:

@Override public boolean isFinished () {return cachedBody.available () == 0; }

5.4. je hotový()

Podobne prepíšeme je hotový() metóda. Táto metóda naznačuje, či InputStream je pripravený na čítanie alebo nie.

Keďže sme už kopírovali InputStream v bajtovom poli sa vrátime pravda označiť, že je vždy k dispozícii:

@Override public boolean isReady () {return true; }

6. Filter

Na záver vytvoríme nový filter, ktorý umožní použitie CachedBodyHttpServletRequest trieda. Tu predĺžime jarné OncePerRequestFilter trieda. Táto trieda má abstraktnú metódu doFilterInternal ().

V tejto metóde budeme vytvoriť objekt CachedBodyHttpServletRequest triedy zo skutočného objektu požiadavky:

CachedBodyHttpServletRequest cachedBodyHttpServletRequest = nový CachedBodyHttpServletRequest (požiadavka);

Tak potom budeme odovzdajte tento nový obalový objekt žiadosti do reťazca filtra. Takže všetky nasledujúce volania na server getInputStreamMetóda () vyvolá prepísanú metódu:

filterChain.doFilter (cachedContentHttpServletRequest, odpoveď);

7. Záver

V tomto tutoriáli sme sa rýchlo prešli cez ContentCachingRequestWrapper trieda. Videli sme aj jeho obmedzenia.

Potom sme vytvorili novú implementáciu HttpServletRequestWrapper trieda. Prelomili sme getInputStream () metóda na vrátenie objektu ServletInputStream trieda.

Nakoniec sme vytvorili nový filter na odovzdanie objektu wrapper požiadavky do reťazca filtra. Požiadavku sme teda mohli prečítať viackrát.

Celý zdrojový kód príkladov nájdete na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found