Czym jest filtr (Filter)?
Filtr to funkcja standardowej specyfikacji J2EE, która umożliwia przetwarzanie dodatkowych zadań dla wszystkich żądań pasujących do wzorca adresu URL przed lub po przekazaniu ich do serwletu dyspozytora (Dispatcher Servlet). Innymi słowy, jest zarządzany przez kontener WWW, taki jak Tomcat, a nie przez kontener Springa, co oznacza, że przetwarza żądania przed dotarciem do serwletu dyspozytora.
Implementacja filtra (Filter)
Aby dodać filtr, należy zaimplementować interfejs Filter z pakietu javax.servlet, który zawiera trzy metody:
- Metoda init
- Jest to metoda służąca do inicjalizacji obiektu filtra i dodawania go do usługi. Kontener WWW wywołuje metodę init tylko raz, aby zainicjalizować obiekt filtra, a następnie wszystkie żądania są przetwarzane za pomocą metody doFilter().
- Metoda doFilter
- Jest to metoda wywoływana przez kontener WWW przed przekazaniem wszystkich żądań HTTP pasujących do wzorca adresu URL do serwletu dyspozytora oraz przed wysłaniem odpowiedzi HTTP przez serwlet dyspozytora do klienta.
Parametrem metody doFilter() jest obiekt FilterChain, który umożliwia przekazanie żądania do następnego celu za pomocą metody doFilter(). Dodając wymagane operacje przed i po chain.doFilter(), możemy wykonać żądane czynności.
- Jest to metoda wywoływana przez kontener WWW przed przekazaniem wszystkich żądań HTTP pasujących do wzorca adresu URL do serwletu dyspozytora oraz przed wysłaniem odpowiedzi HTTP przez serwlet dyspozytora do klienta.
- Metoda destory
- Jest to metoda służąca do usunięcia obiektu filtra z usługi i zwolnienia używanych zasobów. Jest wywoływana tylko raz przez kontener WWW, po czym obiekt filtra nie jest już przetwarzany przez metodę doFilter().
Przykładowy kod - Specyfikacja serwletu
Przykładowy kod - @Component
- @Component: Umożliwia zarejestrowanie filtra jako bean Springa.
- @Order: Umożliwia określenie kolejności, gdy używanych jest wiele filtrów.
- Rejestracja filtra odpowiadającego specyfikacji serwletu jako bean Springa umożliwia korzystanie z innych beanów odpowiadających specyfikacji Springa.
Przykładowy kod - @Configuration
Jeśli filtr ma działać tylko dla określonego URI, można zarejestrować go jako bean Springa za pomocą klasy FilterRegistrationBean.
Zastosowanie filtra (Filter)
Głównie odpowiada za walidację i przetwarzanie parametrów żądania.
- Wspólne zadania związane z bezpieczeństwem
- Ponieważ filtr działa w kontenerze WWW, może on przeprowadzać kontrolę bezpieczeństwa (np. ochrona przed XSS, CSRF), blokując żądania, które nie są prawidłowe. Blokowanie żądania przed dotarciem do kontenera Springa zwiększa stabilność.
- Rejestrowanie wszystkich żądań
- Kompresja obrazów/danych i kodowanie znaków
- Filtr implementuje funkcje, które są powszechnie używane w aplikacji internetowej, takie jak kompresja obrazów lub danych oraz kodowanie znaków.
- Dostosowywanie obiektu ServletRequest
- Obiekt HttpServletRequest umożliwia odczyt zawartości części Body tylko raz. Dlatego filtry i interceptory nie mogą odczytać Body. Możliwe jest utworzenie niestandardowego obiektu ServletRequest w celu zarejestrowania Body.
Interceptor (Przechwytywacz)
Czym jest Interceptor (Przechwytywacz)?
Interceptor (Przechwytywacz) w przeciwieństwie do filtra (Filter), który jest standardową specyfikacją J2EE, jest funkcją dostarczoną przez Springa. Umożliwia odwoływanie się do żądania i odpowiedzi oraz ich przetwarzanie przed i po wywołaniu kontrolera przez serwlet dyspozytora. Innymi słowy, w przeciwieństwie do filtra, który działa w kontenerze WWW, interceptor działa w kontekście Springa.
Serwlet dyspozytora żąda od mapowania obsługi znalezienia odpowiedniego kontrolera i zwraca łańcuch wykonywania (HandlerExecutionChain). Jeśli w tym łańcuchu wykonywania zarejestrowanych jest jeden lub więcej interceptorów, są one wywoływane sekwencyjnie przed wykonaniem kontrolera. Jeśli nie ma interceptorów, kontroler jest wykonywany bezpośrednio.
Implementacja interceptora (Interceptor)
Aby dodać interceptor, należy zaimplementować interfejs HandlerInterceptor z pakietu org.springframework.web.servlet, który zawiera trzy metody:
- Metoda preHandle
- Metoda preHandle jest wykonywana przed wywołaniem kontrolera. Można jej użyć do wykonania operacji przed przetwarzaniem, takich jak przetwarzanie lub dodawanie informacji o żądaniu.
- Trzeci parametr metody preHandle, handler, to obiekt reprezentujący abstrakcyjny opis metody oznaczonej adnotacją @RequestMapping.
- Typ zwracany przez metodę preHandle to boolean. Jeśli zwracana wartość to true, wykonywanie jest kontynuowane, a w przeciwnym razie proces jest przerywany, co oznacza, że kolejne kroki (następny interceptor lub kontroler) nie są wykonywane.
- Metoda postHandle
- Metoda postHandle jest wykonywana po wywołaniu kontrolera. Można jej użyć do wykonania operacji po przetwarzaniu.
- Metoda afterCompletion
- Metoda afterCompletion jest wykonywana po zakończeniu wszystkich operacji, w tym generowania końcowego wyniku we wszystkich widokach.
Przykładowy kod
- Zarejestruj utworzony interceptor jako bean.
- Zarejestruj utworzony interceptor w metodzie addInterceptors() interfejsu WebMvcConfigurer.
- Interceptory działają w kolejności, w jakiej zostały zarejestrowane w obiekcie InterceptorRegistry.
Zastosowanie interceptora (Interceptor)
Głównie odpowiada za przetwarzanie spójności informacji o żądaniach za pomocą logiki usługi.
- Wspólne zadania, takie jak uwierzytelnianie/autoryzacja
- Na przykład, przed przekazaniem żądania do kontrolera, można sprawdzić uwierzytelnienie lub autoryzację, które są związane z żądaniem klienta.
- Rejestrowanie wywołań interfejsu API
- Za pomocą obiektów HttpServletRequest i HttpServletResponse można rejestrować informacje o kliencie.
- Przetwarzanie danych przekazywanych do kontrolera
- Można przetworzyć obiekty HttpServletRequest i HttpServletResponse i przekazać je do kontrolera.
- Naśladowanie AOP
- Trzeci parametr metody preHandle(), HandlerMethod, zawiera dodatkowe informacje, takie jak sygnatura metody, która ma być wykonana, co pozwala na określenie, czy należy wykonać logikę.
Filtr (Filter) vs Interceptor (Przechwytywacz)
- Filtr działa w kontekście WWW, a interceptor w kontekście Springa, co oznacza, że mają różne momenty wykonywania.
- Filtr może obsługiwać przed i po serwlecie dyspozytora, a interceptor przed i po kontrolerze.
- Filtr jest dobrym wyborem do zadań, które muszą być wykonywane globalnie niezależnie od Springa, walidacji samych parametrów wejściowych lub gdy należy użyć ServletRequest zamiast HttpServletRequest.
- Interceptor jest dobrym wyborem do zadań, które muszą być wykonywane globalnie w obrębie Springa lub wymagają mieszania z logiką usługi.
- Interceptor może obsługiwać wyjątki za pomocą adnotacji @ControllerAdvice i @ExceptionHandler, podczas gdy filtr nie może ich używać.
- Filtr zazwyczaj obsługuje wyjątki w bloku try~catch wokół metody doFilter().
Argument Resolver
Czym jest Argument Resolver?
Argument Resolver może pośrednio tworzyć żądane obiekty z wartości przekazanych w żądaniach do kontrolera.
Zastosowanie Argument Resolver
Załóżmy, że żądanie zawiera token JWT. Musimy zweryfikować, czy token jest prawidłowy, a następnie wyodrębnić identyfikator zapisany w tokenie i utworzyć obiekt zalogowanego użytkownika na jego podstawie.
Bez Argument Resolver musielibyśmy zaimplementować proces weryfikacji tokenu i konwersji na obiekt zalogowanego użytkownika w każdym kontrolerze. Powoduje to powielanie kodu w kontrolerach, w których wymagana jest walidacja użytkownika i zwiększa złożoność kontrolerów. Argument Resolver rozwiązuje ten problem.
Implementacja Argument Resolver
ArgumentResolver można użyć poprzez zaimplementowanie interfejsu HandlerMethodArgumentResolver. Ten interfejs wymaga implementacji dwóch metod:
- Metoda supportsParameter
- Dodajemy określoną adnotację przed parametrem, dla którego chcemy, aby ArgumentResolver został uruchomiony. Metoda supportsParameter() sprawdza, czy żądana adnotacja jest dołączona do parametru przekazanej metody. Jeśli tak, zwraca true.
- Metoda resolveArgument
- Jeśli metoda supportsParameter() zwróciła true, co oznacza, że istnieje metoda z dołączoną określoną adnotacją, ta metoda wiąże parametr z żądaną formą i zwraca go.
Po użyciu ArgumentResolver implementacja kontrolera wygląda następująco:
Różnica między Argument Resolver a Interceptor (Przechwytywacz)
- ArgumentResolver działa po interceptorze i zwraca żądany obiekt z wartości przekazanych w żądaniu do kontrolera.
- Z drugiej strony, interceptor przechwytuje żądanie przed faktycznym wykonaniem kontrolera i nie może zwracać żadnych obiektów. Może zwracać tylko wartości logiczne lub void.
Źródła
- https://mangkyu.tistory.com/173
- https://junhyunny.github.io/spring-boot/filter-interceptor-and-aop/
- https://supawer0728.github.io/2018/04/04/spring-filter-interceptor/
- https://tecoble.techcourse.co.kr/post/2021-05-24-spring-interceptor/
- https://baeldung-cn.com/spring-mvc-handlerinterceptor-vs-filter
- https://www.baeldung.com/spring-boot-add-filter
Przewidywane pytania na rozmowę kwalifikacyjną i odpowiedzi
Czym jest filtr?
Filtr to funkcja, która umożliwia przetwarzanie dodatkowych zadań dla wszystkich żądań pasujących do wzorca adresu URL przed lub po przekazaniu ich do serwletu dyspozytora. Działa na poziomie kontenera serwletów.
Kiedy używać filtrów?
Filtry można wykorzystać do obsługi zadań, które muszą być wykonywane globalnie niezależnie od Springa. Można je również użyć do walidacji parametrów żądania.
Typowe zastosowania obejmują: wspólne zadania związane z bezpieczeństwem, rejestrowanie wszystkich żądań, kompresję obrazów/danych i kodowanie znaków, dostosowywanie obiektu ServletRequest.
Czym jest interceptor?
Interceptor to funkcja, która umożliwia odwoływanie się do żądania i odpowiedzi oraz ich przetwarzanie przed i po wywołaniu kontrolera przez serwlet dyspozytora. Działa na poziomie kontenera Springa.
Kiedy używać interceptorów?
Interceptory można wykorzystać do obsługi zadań, które muszą być wykonywane globalnie w kontekście Springa. Są również przydatne, gdy walidacja wymaga wywołania logiki usługi.
Typowe zastosowania obejmują: wspólne zadania związane z uwierzytelnianiem/autoryzacją, rejestrowanie wywołań interfejsu API, przetwarzanie danych przekazywanych do kontrolera.
Jaka jest różnica między filtrem a interceptorem?
Filtr działa na poziomie kontenera serwletów, a interceptor na poziomie kontenera Springa.
Filtr może obsługiwać przed i po serwlecie dyspozytora, a interceptor przed i po kontrolerze.
Dlatego filtry są dobrym wyborem do zadań, które muszą być wykonywane globalnie niezależnie od Springa, a interceptory do zadań, które muszą być wykonywane globalnie w kontekście Springa.
Czym jest Argument Resolver?
Argument Resolver to funkcja, która może pośrednio tworzyć żądane obiekty z wartości przekazanych w żądaniach do kontrolera.
Kiedy używać Argument Resolver?
Można go użyć np. w przypadku żądania z tokenem JWT, aby zweryfikować jego poprawność, wyodrębnić identyfikator z tokenu i utworzyć na jego podstawie obiekt LoginMember.
Jaka jest różnica między interceptorem a Argument Resolver?
ArgumentResolver zwraca żądany obiekt z wartości przekazanych w żądaniu do kontrolera. Interceptor nie może zwracać obiektów, a Argument Resolver jest uruchamiany po nim.
Komentarze0