Bevezetés a Java szűrőmintájának elfogására

1. Áttekintés

Ebben az oktatóanyagban bemutatjuk a Elfogó szűrőminta bemutató szintű Core J2EE minta.

Ez a második oktatóanyag a mi oldalunkon Minta sorozat és a Az első vezérlő mintája útmutató, amely megtalálható itt.

Elfogó szűrők olyan szűrők, amelyek kiváltják a műveleteket egy bejövő kérés kezelő általi feldolgozása előtt vagy után.

Az elfogó szűrők egy webalkalmazás központosított összetevőit képviselik, amelyek minden kérésnél közösek és kiterjeszthetők anélkül, hogy a meglévő kezelőket befolyásolnák.

2. Használjon tokokat

Bővítsük az előző útmutató példáját és valósítsuk meg hitelesítési mechanizmus, kérésnaplózás és látogatószámláló. Ezenkívül szeretnénk az oldalunk megjelenítésének képességét különféle különböző kódolás.

Mindezek a szűrők lehallgatásának használati esetei, mivel minden kérelemben közösek és függetlenek a kezelőktől.

3. Szűrési stratégiák

Vezessünk be különböző szűrési stratégiákat és példamutató felhasználási eseteket. A kód futtatásához a Jetty Servlet tárolóval egyszerűen hajtsa végre:

$> mvn móló telepítése: futtatás

3.1. Egyéni szűrési stratégia

Az egyéni szűrési stratégiát minden olyan esetben használjuk, amely a kérelmek rendezett feldolgozását igényli a az egyik szűrő egy végrehajtási lánc előző szűrőjének eredményein alapul.

Ezeket a láncokat a FilterChain felület és különféle regisztráció Szűrő osztályok vele.

Ha több, különböző aggodalommal járó szűrőláncot használ, egyesítheti őket egy szűrőkezelőben:

Példánkban a látogatószámláló a bejelentkezett felhasználók egyedi felhasználóneveinek számlálásával működik, ami azt jelenti, hogy a hitelesítési szűrő eredményén alapul, ezért mindkét szűrőt láncolni kell.

Végezzük el ezt a szűrőláncot.

Először létrehozunk egy hitelesítési szűrőt, amely ellenőrzi, hogy a munkamenet létezik-e egy beállított „felhasználónév” attribútumhoz, és ha nem, akkor bejelentkezési eljárást ad ki

public class AuthenticationFilter végrehajtja a (z) {... @Orride public void doFilter (ServletRequest kérés, ServletResponse válasz, FilterChain lánc) felülbírálása {HttpServletRequest httpServletRequest = (HttpServletRequest) kérést; HttpServletResponse httpServletResponse = (HttpServletResponse) válasz; HttpSession session = httpServletRequest.getSession (hamis); if (session == null || session.getAttribute ("felhasználónév") == null) {FrontCommand parancs = új LoginCommand (); command.init (httpServletRequest, httpServletResponse); parancs.folyamat (); } else {chain.doFilter (kérés, válasz); }} ...}

Most hozzuk létre a látogatószámlálót. Ez a szűrő fenntartja a HashSet egyedi felhasználónév, és hozzáad egy „számláló” attribútumot a kéréshez:

public class VisitorCounterFilter implementálja a Filter {private static Set users = new HashSet (); ... @Orride public void doFilter (ServletRequest kérés, ServletResponse válasz, FilterChain lánc) {HttpSession session = (((HttpServletRequest) kérés) .getSession (hamis); Opcionális.ofNullable (session.getAttribute ("felhasználónév")) .map (Object :: toString) .ifPresent (users :: add); request.setAttribute ("számláló", users.size ()); chain.doFilter (kérés, válasz); } ...}

Ezután megvalósítjuk a FilterChain hogy a regisztrált szűrőket ismétli és végrehajtja doFilter módszer:

public class FilterChainImpl implementálja a FilterChain {private Iterator szűrőket; public FilterChainImpl (Filter ... filters) {this.filters = Arrays.asList (filters) .iterator (); } @Orride public void doFilter (ServletRequest kérés, ServletResponse válasz) {if (filters.hasNext ()) {Filter filter = filters.next (); filter.doFilter (kérés, válasz, ez); }}}

Komponenseink összekapcsolása érdekében hozzunk létre egy egyszerű statikus kezelőt, amely felelős a szűrőláncok példányosításáért, a szűrők regisztrálásáért és elindításáért:

public class FilterManager {public static void process (HttpServletRequest request, HttpServletResponse response, OnIntercept callback) {FilterChain filterChain = new FilterChainImpl (new AuthenticationFilter (callback), new VisitorCounterFilter ()); filterChain.doFilter (kérés, válasz); }}

Utolsó lépésként hívnunk kell FilterManager a kérelmek feldolgozásának sorrendjében belülről FrontCommand:

public abstract class FrontCommand {... public void process () {FilterManager.process (kérés, válasz); } ...}

3.2. Alapszűrő stratégia

Ebben a részben bemutatjuk a Alapszűrő stratégia, amellyel az összes megvalósított szűrőhöz közös szuperosztályt használnak.

Ez a stratégia jól játszik együtt az előző szakasz egyéni stratégiájával vagy a Standard szűrő stratégia amelyet a következő szakaszban mutatunk be.

Az absztrakt alaposztály használható a szűrő lánchoz tartozó egyéni viselkedés alkalmazására. Példánkban a szűrőkonfigurációhoz és a hibakereséshez kapcsolódó naplózási kód csökkentésére használjuk:

public abstract base BaseFilter osztály megvalósítja a Filter {private Logger log = LoggerFactory.getLogger (BaseFilter.class); védett FilterConfig filterConfig; @Orride public void init (FilterConfig filterConfig) dobja a ServletException {log.info ("Inicializálja a szűrőt: {}", getClass (). GetSimpleName ()); this.filterConfig = filterConfig; } @Orride public void destr (() {log.info ("Szűrő megsemmisítése: {}", getClass (). GetSimpleName ()); }}

Bővítsük ezt az alaposztályt egy kérelem naplózási szűrő létrehozására, amelyet a következő szakaszba integrálunk:

public class LoggingFilter kiterjeszti a BaseFilter {private static final Logger log = LoggerFactory.getLogger (LoggingFilter.class); @Orride public void doFilter (ServletRequest kérés, ServletResponse válasz, FilterChain lánc) {chain.doFilter (kérés, válasz); HttpServletRequest httpServletRequest = (HttpServletRequest) kérés; Karakterlánc felhasználónév = Opcionális .ofNullable (httpServletRequest.getAttribute ("felhasználónév")) .map (Object :: toString) .orElse ("vendég"); log.info ("Kérés a következőtől:" {} @ {} ": {}? {}", felhasználónév, request.getRemoteAddr (), httpServletRequest.getRequestURI (), request.getParameterMap ()); }}

3.3. Standard szűrő stratégia

A szűrők alkalmazásának rugalmasabb módja a Standard szűrő stratégia. Ez úgy történhet, hogy deklaráljuk a szűrőket egy telepítési leíróban, vagy a Servlet 3.0 specifikáció óta annotációval.

A szokásos szűrési stratégialehetővé teszi új szűrők beépítését egy alapértelmezett láncba anélkül, hogy kifejezetten meghatározott szűrőkezelő lenne:

Vegye figyelembe, hogy a sorrend, amelyben a szűrőket alkalmazzák, nem határozható meg kommentárokkal. Ha megrendelt végrehajtásra van szüksége, ragaszkodnia kell egy telepítési leíróhoz, vagy egyéni szűrési stratégiát kell végrehajtania.

Vezessünk be egy annotáció által vezérelt kódolási szűrőt, amely az alapszűrő stratégiát is használja:

@WebFilter (servletNames = {"intercepting-filter"}, initParams = {@WebInitParam (name = "encoding", value = "UTF-8")}) public class EncodingFilter kiterjeszti a BaseFilter {private String kódolást; A @Orride public void init (FilterConfig filterConfig) dobja a ServletException {super.init (filterConfig); this.encoding = filterConfig.getInitParameter ("kódolás"); } @Orride public void doFilter (ServletRequest kérés, ServletResponse válasz, FilterChain lánc) {String encoding = Opcionális .ofNullable (request.getParameter ("kódolás")) .orElse (this.encoding); response.setCharacterEncoding (kódolás); chain.doFilter (kérés, válasz); }}

Servlet-forgatókönyv esetén telepítési leíróval rendelkezünk web.xml tartalmazza ezeket az extra nyilatkozatokat:

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

Vedd fel a naplózási szűrőnket, és jegyezzük fel azt is, hogy a Servlet megszokja:

@WebFilter (servletNames = "intercepting-filter") public class LoggingFilter kiterjeszti a BaseFilter {...}

3.4. Sablonszűrő stratégia

A Sablonszűrő stratégia nagyjából megegyezik az alapszűrő stratégiával, azzal a különbséggel, hogy az alaposztályban deklarált sablon módszereket használja, amelyeket felül kell írni a megvalósításokban:

Hozzunk létre egy alapszűrő osztályt két absztrakt szűrőmódszerrel, amelyeket további feldolgozás előtt és után hívunk meg.

Mivel ez a stratégia ritkábban fordul elő, és a példánkban nem használjuk, a konkrét megvalósítási és felhasználási eset az Ön fantáziáján múlik:

a TemplateFilter nyilvános absztrakt osztály kiterjeszti a BaseFilter {védett absztrakt void preFilter (HttpServletRequest kérés, HttpServletResponse válasz); védett absztrakt void postFilter (HttpServletRequest kérés, HttpServletResponse válasz); @Orride public void doFilter (ServletRequest kérés, ServletResponse válasz, FilterChain lánc) {HttpServletRequest httpServletRequest = (HttpServletRequest) kérés; HttpServletResponse httpServletResponse = (HttpServletResponse) válasz; preFilter (httpServletRequest, httpServletResponse); chain.doFilter (kérés, válasz); postFilter (httpServletRequest, httpServletResponse); }}

4. Következtetés

Az elfogó szűrőminta átfogó aggályokat ragad meg, amelyek az üzleti logikától függetlenül fejlődhetnek. Az üzleti műveletek szempontjából a szűrőket az elő- vagy utólagos műveletek láncaként hajtják végre.

Amint eddig láthattuk, a Elfogó szűrőminta különböző stratégiák alkalmazásával valósítható meg. A „valós világ” alkalmazásaiban ezek a különböző megközelítések kombinálhatók.

Szokás szerint megtalálja a forrásokat a GitHubon.