Uvod u presretanje uzorka filtra na Javi

1. Pregled

U ovom uputstvu predstavit ćemo Presretanje uzorka filtra uzorak jezgre prezentacije na razini J2EE.

Ovo je drugi tutorial u našem Niz uzoraka i nastavak Uzorak prednjeg kontrolera vodič koji se može naći ovdje.

Presretanje filtera su filtri koji pokreću radnje prije ili nakon što dolazni zahtjev obrađuje rukovatelj.

Filtri za presretanje predstavljaju centralizirane komponente u web aplikaciji, zajedničke svim zahtjevima i proširive bez utjecaja na postojeće rukovatelje.

2. Koristite slučajeve

Proširimo primjer iz prethodnog vodiča i provedbe mehanizam provjere autentičnosti, evidentiranje zahtjeva i brojač posjetitelja. Uz to, želimo mogućnost isporuke naših stranica u raznim različitim kodiranje.

Sve su ovo slučajevi upotrebe za presretanje filtara, jer su zajednički svim zahtjevima i trebali bi biti neovisni o voditeljima.

3. Strategije filtriranja

Uvedimo različite strategije filtriranja i uzorne slučajeve uporabe. Da biste pokrenuli kod s spremnikom Jetty Servlet, jednostavno izvršite:

$> mvn instaliraj pomol: pokrenite

3.1. Strategija prilagođenog filtra

Prilagođena strategija filtriranja koristi se u svakom slučaju upotrebe koji zahtijeva uređenu obradu zahtjeva, u značenju jedan se filtar temelji na rezultatima prethodnog filtra u izvršnom lancu.

Ti će lanci biti stvoreni primjenom FilterChain sučelje i registriranje raznih filtar klase s njom.

Kada upotrebljavate više lanaca filtara s različitim problemima, možete ih spojiti u upravitelju filtra:

U našem primjeru brojač posjetitelja radi brojeći jedinstvena korisnička imena prijavljenih korisnika, što znači da se temelji na rezultatu filtra za provjeru autentičnosti, stoga oba filtra moraju biti u lancu.

Primijenimo ovaj lanac filtara.

Prvo ćemo stvoriti filtar za provjeru autentičnosti koji provjerava postoji li sesija za postavljeni skup atributa 'korisničko ime' i izdati proceduru prijave ako ne:

javna klasa AuthenticationFilter provodi Filter {... @Override public void doFilter (zahtjev ServletRequest, odgovor ServletResponse, lanac FilterChain) {HttpServletRequest httpServletRequest = (HttpServletRequest) zahtjev; HttpServletResponse httpServletResponse = (HttpServletResponse) odgovor; HttpSession session = httpServletRequest.getSession (false); if (session == null || session.getAttribute ("username") == null) {FrontCommand command = new LoginCommand (); command.init (httpServletRequest, httpServletResponse); command.process (); } else {chain.doFilter (zahtjev, odgovor); }} ...}

Ajmo sada stvoriti brojač posjetitelja. Ovaj filtar održava a HashSet jedinstvenih korisničkih imena i dodaje atribut "brojač" zahtjevu:

javna klasa VisitorCounterFilter provodi Filter {private static Set users = new HashSet (); ... @Override public void doFilter (ServletRequest zahtjev, ServletResponse odgovor, FilterChain lanac) {HttpSession session = ((HttpServletRequest) zahtjev) .getSession (false); Izborno.ofNullable (session.getAttribute ("korisničko ime")) .map (Object :: toString) .ifPresent (users :: add); request.setAttribute ("brojač", users.size ()); chain.doFilter (zahtjev, odgovor); } ...}

Dalje ćemo implementirati a FilterChain koji ponavlja iteljene filtre i izvršava ih doFilter metoda:

javna klasa FilterChainImpl implementira FilterChain {filteri private Iterator; javni FilterChainImpl (Filtriraj ... filtri) {this.filters = Arrays.asList (filtri) .iterator (); } @Override public void doFilter (zahtjev za ServletRequest, odgovor ServletResponse) {if (filters.hasNext ()) {Filter filter = filters.next (); filter.doFilter (zahtjev, odgovor, ovo); }}}

Da bismo povezali naše komponente, stvorimo jednostavan statički upravitelj koji je odgovoran za instanciranje lanaca filtara, registraciju njegovih filtara i njegovo pokretanje:

javna klasa FilterManager {javni statički void postupak (zahtjev HttpServletRequest, odgovor HttpServletResponse, povratni poziv OnIntercept) {FilterChain filterChain = novi FilterChainImpl (novi AuthenticationFilter (povratni poziv), novi VisitorCounterFilter ()); filterChain.doFilter (zahtjev, odgovor); }}

Kao posljednji korak morat ćemo nazvati naš FilterManager kao uobičajeni dio slijeda obrade zahtjeva iz našeg FrontCommand:

javna apstraktna klasa FrontCommand {... public void process () {FilterManager.process (zahtjev, odgovor); } ...}

3.2. Strategija osnovnog filtra

U ovom ćemo odjeljku predstaviti Strategija osnovnog filtra, s kojim se koristi zajednička superklasa za sve implementirane filtre.

Ova se strategija lijepo poklapa s prilagođenom strategijom iz prethodnog odjeljka ili s Standardna strategija filtra koje ćemo predstaviti u sljedećem odjeljku.

Apstraktna osnovna klasa može se koristiti za primjenu prilagođenog ponašanja koje pripada lancu filtra. Upotrijebit ćemo ga u našem primjeru za smanjivanje uzorka koda koji se odnosi na konfiguraciju filtra i prijavu pogrešaka:

javna apstraktna klasa BaseFilter provodi Filter {private Logger log = LoggerFactory.getLogger (BaseFilter.class); zaštićeni FilterConfig filterConfig; @Override public void init (FilterConfig filterConfig) baca ServletException {log.info ("Initialize filter: {}", getClass (). GetSimpleName ()); this.filterConfig = filterConfig; } @Override public void uništavanje () {log.info ("Uništi filtar: {}", getClass (). GetSimpleName ()); }}

Proširimo ovu osnovnu klasu kako bismo stvorili filtar zapisivanja zahtjeva, koji će biti integriran u sljedeći odjeljak:

javna klasa LoggingFilter proširuje BaseFilter {private static final Logger log = LoggerFactory.getLogger (LoggingFilter.class); @Override public void doFilter (zahtjev ServletRequest, odgovor ServletResponse, lanac FilterChain) {chain.doFilter (zahtjev, odgovor); HttpServletRequest httpServletRequest = (HttpServletRequest) zahtjev; String korisničko ime = Izborno .ofNullable (httpServletRequest.getAttribute ("korisničko ime")) .map (Object :: toString) .orElse ("gost"); log.info ("Zahtjev od '{} @ {}': {}? {}", korisničko ime, request.getRemoteAddr (), httpServletRequest.getRequestURI (), request.getParameterMap ()); }}

3.3. Strategija standardnog filtra

Fleksibilniji način primjene filtara je implementacija Strategija standardnog filtra. To se može učiniti deklariranjem filtara u deskriptoru implementacije ili, od specifikacije Servlet 3.0, anotacijom.

Standardna strategija filtriranjaomogućuje priključivanje novih filtara u zadani lanac bez izričito definiranog upravitelja filtara:

Imajte na umu da se redoslijed primjene filtara ne može navesti bilješkama. Ako vam je potrebno naređeno izvršenje, morate se držati deskriptora implementacije ili implementirati prilagođenu strategiju filtra.

Primijenimo filtar kodiranja vođen bilješkama koji također koristi osnovnu strategiju filtra:

@WebFilter (servletNames = {"intercepting-filter"}, initParams = {@WebInitParam (name = "encoding", value = "UTF-8")}) javna klasa EncodingFilter proširuje BaseFilter {private String encoding; @Override public void init (FilterConfig filterConfig) baca ServletException {super.init (filterConfig); this.encoding = filterConfig.getInitParameter ("kodiranje"); } @Override public void doFilter (ServletRequest zahtjev, ServletResponse odgovor, FilterChain lanac) {String encoding = Izborno .ofNullable (request.getParameter ("encoding")) .orElse (this.encoding); response.setCharacterEncoding (kodiranje); chain.doFilter (zahtjev, odgovor); }}

U scenariju Servleta koji ima deskriptor implementacije, naš web.xml sadržavao bi ove dodatne izjave:

 encoding-filter com.baeldung.patterns.intercepting.filter.filters.EncodingFilter encoding-filter interceptting-filter 

Podignimo naš filtar za bilježenje i označimo ga također, kako bismo se Servletom koristili:

@WebFilter (servletNames = "intercepting-filter") javna klasa LoggingFilter proširuje BaseFilter {...}

3.4. Strategija filtra predloška

The Strategija filtra predloška je gotovo jednak strategiji osnovnog filtra, osim što koristi metode predloška deklarirane u osnovnoj klasi koje se moraju nadjačati u implementacijama:

Stvorimo osnovnu klasu filtra s dvije apstraktne metode filtriranja koje se pozivaju prije i nakon daljnje obrade.

Budući da je ova strategija rjeđa i ne koristimo je u našem primjeru, konkretan slučaj implementacije i upotrebe ovisi o vašoj mašti:

javna apstraktna klasa TemplateFilter proširuje BaseFilter {zaštićeni sažetak void preFilter (zahtjev HttpServletRequest, odgovor HttpServletResponse); zaštićeni apstraktni void postFilter (zahtjev HttpServletRequest, odgovor HttpServletResponse); @Override public void doFilter (zahtjev za ServletRequest, odgovor ServletResponse, lanac FilterChain) {HttpServletRequest httpServletRequest = (HttpServletRequest) zahtjev; HttpServletResponse httpServletResponse = (HttpServletResponse) odgovor; preFilter (httpServletRequest, httpServletResponse); chain.doFilter (zahtjev, odgovor); postFilter (httpServletRequest, httpServletResponse); }}

4. Zaključak

Uzorak filtra za presretanje bilježi unakrsne probleme koji se mogu razvijati neovisno o poslovnoj logici. Iz perspektive poslovnog poslovanja, filtri se izvode kao lanac radnji prije ili poslije.

Kao što smo do sada vidjeli, Presretanje uzorka filtra mogu se implementirati pomoću različitih strategija. U aplikacijama iz 'stvarnog svijeta' ti se različiti pristupi mogu kombinirati.

Kao i obično, pronaći ćete izvore na GitHubu.