Filtre, J2E'den alınmıştır ve Servlet'in "geliştirilmiş sürümü" olarak kabul edilebilir. Esas olarak kullanıcı isteklerini ön işleme ve sonradan işlemek için kullanılır ve tipik bir işleme zincirine sahiptir. Filtre ayrıca, Servlet ile aynı olan, kullanıcı isteklerine yanıtlar da oluşturabilir, ancak pratikte Filtre, kullanıcı isteklerine yanıt oluşturmak için nadiren kullanılır.
Filtre kullanmanın tam süreci şudur: Filtre, kullanıcı talebini önceden işler, ardından isteği ön işleme için Servlet'e iletir ve bir yanıt oluşturur ve son olarak Filter, sunucu yanıtını sonradan işler.
Çeşitli filtrelerin işlevleri JavaDoc'ta verilmiştir.
Bu tasarım için belirlenmiş örnekler
1) Kimlik Doğrulama Filtreleri, yani kullanıcı erişim izinleri filtreleme
2) Günlük Kaydı ve Denetleme Filtreleri, günlük filtreleme, özel kullanıcıların özel isteklerini vb. Kaydedebilir.
3) Görüntü dönüştürme Filtreleri
4) Veri sıkıştırma Filtreleri
5) Şifreleme Filtreleri
6) Tokenleştirme Filtreleri
7) Kaynak erişim olaylarını tetikleyen filtreler
8) XSL / T filtreleri
9) Mime tipi zincir filtresi
İlk öğe için, yani izin filtreleme için Filtre kullanmak, şu şekilde uygulanabilir: Her bir istemci tarafından başlatılan istek URL'sini almak için bir Filtre tanımlayın ve bunu mevcut kullanıcının erişim iznine sahip olmadığı URL'lerin listesiyle karşılaştırın (DB'den alınabilir) , İzin filtreleme rolünü oynar.
Tüm özel filtreler javax.Servlet.Filter arayüzünü uygulamalı ve arayüzde tanımlanan üç yöntemi yeniden yazmalıdır:
1. init'ten kaçının (FilterConfig yapılandırması)
Filtrenin başlatılmasını tamamlamak için kullanılır.
2. yok etmekten kaçının ()
Filtre yok edilmeden önce belirli kaynakların kurtarılmasını tamamlamak için kullanılır.
3. doFilter'den kaçının (ServletRequest isteği, ServletResponse yanıtı, FilterChain zinciri)
Filtreleme işlevini, yani her istek ve yanıt için ek ön işleme ve son işlemeyi gerçekleştirin. , Bu yöntemi çalıştırmadan önce, kullanıcı talebi önceden işlenir; bu yöntemi uyguladıktan sonra, sunucu yanıtı sonradan işlenir.
Chain.doFilter () yönteminin ön işleme aşamasından önce yürütüldüğüne dikkat etmek önemlidir.Yöntem çalıştırmanın sonu, kullanıcının isteğinin denetleyici tarafından işlendiği anlamına gelir. Bu nedenle, doFilter'da chain.doFilter () yöntemini çağırmayı unutursanız, kullanıcının isteği işlenmeyecektir.
importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importorg.springframework.stereotype.Component; importjavax.servlet. *; importjavax.servlet.http.HttpServletRequest; importjava.io.IOException; // Web üzerinden bir yorum eklemelisiniz. xml yapılandırması @ComponentpublicclassTimeFilterimplementsFilter {privatestaticfinalLoggerLOG = LoggerFactory.getLogger (TimeFilter.class); @ Overridepublicvoidinit (FilterConfigfilterConfig) throwsServletException {LOG.info ("İlk filtrelemeFiltresi: {}", Overridepublicvoidinit); , FilterChainchain) throwsIOException, ServletException {LOG.info ("starttodoFilter"); longstartTime = System.currentTimeMillis (); chain.doFilter (istek, yanıt); longendTime = System.currentTimeMillis (); LOG.info ("therequestof {} tüketir {} ms. ", getUrlFrom (istek), (endTime-startTime)); LOG.info (" endtodoFilter ");} @ Overridepublicvoiddestroy () {LOG.info (" Destroy filter ");} privateStringgetUrlFrom (ServletRequestservletRequest) { eğer (servletRequestinstanceofHttpServletRequest) {return ((HttpSe rvletRequest) servletRequest) .getRequestURL (). toString ();} return "";}}Filtre sınıfının javax.servlet. * İçinde olduğu koddan görülebilir, bu nedenle filtrenin büyük bir sınırlamasının mevcut kullanıcı isteğinin hangi denetleyici (Denetleyici) olduğunu bilememesi olduğu görülebilir. İşleme, çünkü ikincisi yay çerçevesinde tanımlanır.
SpringMvc için filtreyi web.xml dosyasında kaydedebilirsiniz. Ancak, SpringBoot'ta web.xml yoktur. Şu anda, bir jar paketindeki bir filtreye başvurulursa ve filtre @Component tarafından Spring Bean olarak tanımlanmazsa, filtre etkili olmayacaktır.
Şu anda, filtreyi java kodu aracılığıyla kaydetmeniz gerekir. Örnek olarak yukarıda tanımlanan TimeFilter'ı ele alalım, @Component sınıf ek açıklaması kaldırıldığında kayıt yöntemi:
@ConfigurationpublicclassWebConfig {/ *** Bir üçüncü taraf filtresi kaydedin * İşlev, web.xml*@return * / @ BeanpublicFilterRegistrationBeanthirdFilter () {ThirdPartFilterthirdPartFilter = newThirdPeanfilterset (); FilterReanReanFilter (); filtresini yapılandırarak springmvc'deki ile aynıdır. );Liste < Dize > urls = newArrayList < > (); // Tüm istek yollarını eşleştir urls.add ("/ *"); filterRegistrationBean.setUrlPatterns (urls); returnfilterRegistrationBean;}}@Component ek açıklaması ile karşılaştırıldığında, bu yapılandırma yönteminin bir avantajı vardır, yani yakalanan URL serbestçe yapılandırılabilir.
Interceptor, AOP'de (Görünüş Odaklı Programlama) bir yöntemi veya alanı erişilmeden önce durdurmak ve ardından belirli işlemleri öncesine veya sonrasına eklemek için kullanılır. Durdurma, AOP'nin bir uygulama stratejisidir.
HandlerInterceptor arabirimini uygulayarak ve arabirimin üç yöntemini yeniden yazarak durdurucuyu özelleştirin:
1.preHandler (HttpServletRequest isteği, HttpServletResponse yanıtı, Nesne işleyicisi)
Yöntem, talep işlenmeden önce çağrılacaktır. SpringMVC'deki Interceptor, zincir çağrısındaki Filter ile aynıdır. Her Interceptor çağrısı, bildirim sırasına göre sırayla yürütülecektir ve ilk çalıştırılacak olan Interceptor'daki preHandle yöntemidir, bu nedenle bazı ön başlatma işlemleri veya mevcut talebin bir ön işlemi bu yöntemde gerçekleştirilebilir. Talebin devam edip etmeyeceğine karar vermek için bu yöntemde bazı yargılarda bulunabilirsiniz.
Bu yöntemin dönüş değeri Boolean tipindedir.Yanlış döndürdüğünde, isteğin bittiğini ve ardından Interceptor ve Controller'ın çalıştırılmayacağını; dönüş değeri true olduğunda, bir sonraki Interceptor'ın preHandle yöntemi çağrılmaya devam edilecektir. , Son Durdurucu ise, şu anda talep edilen Denetleyici yöntemini çağıracaktır.
2.postHandler (HttpServletRequest isteği, HttpServletResponse yanıtı, Nesne işleyicisi, ModelAndView modelAndView)
Geçerli istek işlendikten sonra, Controller yöntemi çağrıldıktan sonra yürütülür, ancak DispatcherServlet görünüm dönüşü işlemesini gerçekleştirmeden önce çağrılır, böylece Controller bu yöntemde işlendikten sonra ModelAndView nesnesi üzerinde işlem yapabiliriz.
3.afterCompletion (HttpServletRequest isteği, HttpServletResponse yanıtı, Nesne tutamacı, Exception ex)
Bu yöntemin, karşılık gelen Interceptor'ın preHandle yönteminin dönüş değeri doğru olduğunda da yürütülmesi gerekir. Adından da anlaşılacağı gibi, bu yöntem tüm istek sona erdikten sonra, yani DispatcherServlet ilgili görünümü oluşturduktan sonra çalıştırılacaktır. Bu yöntemin ana işlevi kaynakları temizlemektir.
@ComponentpublicclassTimeInterceptorimplementsHandlerInterceptor {privatestaticfinalLoggerLOG = LoggerFactory.getLogger (TimeInterceptor.class); @ OverridepublicbooleanpreHandle (HttpServletRequestrequest (HttpServletRequest), "Objeyi işlemeden önce HttpServletRequest" "," HttpServletResponsCecception "isteği startTime ", System.currentTimeMillis ()); HandlerMethodhandlerMethod = (HandlerMethod) işleyici; LOG.info (" controllerobjectis {} ", handlerMethod.getBean (). getClass (). getName ()); LOG.info (" controllermethodis {} ' Ancak, görünüm oluşturulmadan önce (Controller yöntemi çağrıldıktan sonra), bir istisna meydana gelirse, yöntem çağrılmaz ");} @ OverridepublicvoidafterCompletion (HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler, Exceptionex) isteğin tamamında (" İsteğin tamamında "LOG.info özel durumu) atar Daha sonra çağrılır, yani DispatcherServlet ilgili görünümü oluşturduktan sonra çalıştırılır (esas olarak kaynak temizliği için) "); longs tartTime = (long) request.getAttribute ("startTime"); LOG.info ("timeconsumeis {}", System.currentTimeMillis () - startTime);}Filtreden farklı olarak, engelleyici @Component ile dekore edildikten sonra, WebMvcConfigurer uygulanarak SpringBoot'a manuel olarak kaydedilmesi gerekir:
// java yapılandırma sınıfı @ ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer {@AutowiredprivateTimeInterceptortimeInterceptor; @OverridepublicvoidaddInterceptors (InterceptorRegistryregistry) {registry.addInterceptor (timeInterceptor);}}SpringMVC'de ise, xml dosyası aracılığıyla yapılandırmanız gerekir < mvc: engelleyiciler > Düğüm bilgileri.
Filtrelerle karşılaştırıldığında, engelleyici, kullanıcı tarafından gönderilen talebin nihai olarak hangi denetleyici tarafından işlendiğini bilebilir, ancak önleyicinin bariz bir kusuru vardır, yani, isteğin parametrelerini ve denetleyici işledikten sonra yanıtı elde edemez. Yani dilimlemek için bir yer var.
Dilimleme uygulamasında, @Aspect, @Component ve @Around olmak üzere üç ek açıklamanın kullanımına dikkat edilmelidir. Ayrıntılar için resmi belgeleri kontrol edin:
https://docs.spring.io/spring/docs/5.0.12.RELEASE/spring-framework-reference/core.html#aop
@ Aspect @ ComponentpublicclassTimeAspect {privatestaticfinalLoggerLOG = LoggerFactory.getLogger (TimeAspect.class); @ Around ("execution (* me.ifight.controller. *. * (..)") publicObjecthandleControllerMethod (ProceedingJoinPoint) (ProceedingJoinPoint) Dilim başlangıcı ... "); longstartTime = System.currentTimeMillis (); // İstek girdisini al Objectargs = progressingJoinPoint.getArgs (); Arrays.stream (args) .forEach (arg- > LOG.info ("argis {}", arg)); // İlgili Objectresponse = progressingJoinPoint.proceed (); longendTime = System.currentTimeMillis (); LOG.info ("İstek: {}, zaman alan {} ms" , progressingJoinPoint.getSignature (), (endTime-startTime)); LOG.info ("Dilimin sonu ..."); returnnull;}}Aşağıdaki şekil, üç Filtrenin arama sırasını göstermektedir. > Intercepto- > Görünüş- > Denetleyici. Aksine, Kontrolör tarafından atılan istisnaların işleme sırası içeriden dışarıya doğrudur. Bu nedenle, denetleyici tarafından oluşturulan istisnaları tek tip olarak işlemek için her zaman bir @ControllerAdvice ek açıklaması tanımlarız.
İstisna @ControllerAdvice tarafından işlenirse, çağrı durdurucunun afterCompletion yönteminin Exception istisnası parametresi boş olacaktır.
Çağrı yığınının gerçek uygulaması da bu noktayı göstermektedir:
Filtreler ve önleyiciler için ayrıntılı arama sırası aşağıdaki gibidir:
Son olarak, filtreler ve önleyiciler arasındaki farktan bahsetmek gerekir:
Ek olarak, filtrelerle karşılaştırıldığında, önleyiciler kullanıcının isteğini Spring çerçevesinin hangi denetleyicisinin işlediğini "görebilir".