溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

SpringBoot攔截器如何使用

發(fā)布時間:2022-01-04 19:07:25 來源:億速云 閱讀:132 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“SpringBoot攔截器如何使用”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“SpringBoot攔截器如何使用”吧!

    定義攔截器

    攔截器:所謂攔截器,就是能夠在進(jìn)行某個操作之前攔截請求,如果請求符合條件就允許在往下執(zhí)行。比如說,海關(guān)就是一個攔截器,他攔截進(jìn)出口的貨物,如果貨物滿足進(jìn)出口條件,則放行,否則就攔截,退回處理。

    定義攔截器的幾種方式:

    實(shí)現(xiàn)HandleInterceptor接口

    自定義攔截器類實(shí)現(xiàn)HandleInterceptor接口,并使用@Component注解標(biāo)注為一個組件。

    public class MySelfInterceptor implements HandlerInterceptor {
    	@Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        	System.out.println("在業(yè)務(wù)處理器處理請求之前被調(diào)用");
        	return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    		System.out.println("在業(yè)務(wù)處理器處理請求執(zhí)行完成后,生成視圖之前執(zhí)行");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    		System.out.println("在DispatcherServlet完全處理完請求后被調(diào)用");
        }
    }

    根據(jù)三種情況,可以在不同的方法針對請求進(jìn)行額外的處理。
    在preHandle中,可以進(jìn)行權(quán)限校驗(yàn),安全控制。
    在postHandle中,可以對返回來的ModelAndView進(jìn)行處理,這個時候還未渲染視圖。
    在afterCompletion中,請求已經(jīng)完成,頁面已經(jīng)渲染,數(shù)據(jù)已經(jīng)返回。這個時候可以做一些資源清理,或者記錄請求調(diào)用時間,做性能監(jiān)控

    繼承HandleInterceptorAdapter類

    自定義攔截器類繼承HandleInterceptor接口的實(shí)現(xiàn)類HandleInterceptorAdapter來定義,并使用@Component注解標(biāo)注為一個組件。建議使用此方式可以根據(jù)需要覆蓋一些方法

    @Component
    public class MyInterceptor extends HandlerInterceptorAdapter {
    
        public SingleLoginInterceptor() {
            super();
        }
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            return super.preHandle(request, response, handler);
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            super.postHandle(request, response, handler, modelAndView);
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            super.afterCompletion(request, response, handler, ex);
        }
    
        @Override
        public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            super.afterConcurrentHandlingStarted(request, response, handler);
        }
    }

    可以看到HandlerInterceptorAdapter類底層是實(shí)現(xiàn)了HandlerInterceptor接口,多了兩個方法,要比
    實(shí)現(xiàn)HandlerInterceptor接口的方式功能強(qiáng)大。
    這兩個方法都是HandlerInterceptorAdapter類實(shí)現(xiàn)的org.springframework.web.servlet.AsyncHandlerInterceptor接口提供的,而AsyncHandlerInterceptor接口又繼承了HandlerInterceptor接口,所以HandlerInterceptorAdapter底層是實(shí)現(xiàn)類HandlerInterceptor接口。

    實(shí)現(xiàn)WebRequestInterceptor接口

    自定義攔截器類實(shí)現(xiàn)WebRequestInterceptor接口,并使用@Component注解標(biāo)注為一個組件。

    @Component
    public class MyInterceptor implements WebRequestInterceptor {
        
        @Override
        public void preHandle(WebRequest webRequest) throws Exception {
            
        }
    
        @Override
        public void postHandle(WebRequest webRequest, ModelMap modelMap) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(WebRequest webRequest, Exception e) throws Exception {
    
        }
    }

    兩個實(shí)現(xiàn)接口方式的異同點(diǎn) 相同點(diǎn) 都可以實(shí)現(xiàn)controller層的攔截請求 不同點(diǎn)
    1.WebRequestInterceptor的入?yún)ebRequest是包裝了HttpServletRequest 和HttpServletResponse的,通過WebRequest獲取Request中的信息更簡便。
    2.WebRequestInterceptor的preHandle是沒有返回值的,說明該方法中的邏輯并不影響后續(xù)的方法執(zhí)行,所以這個接口實(shí)現(xiàn)就是為了獲取Request中的信息,或者預(yù)設(shè)一些參數(shù)供后續(xù)流程使用。
    3.HandlerInterceptor的功能更強(qiáng)大也更基礎(chǔ),可以在preHandle方法中就直接拒絕請求進(jìn)入controller方法。
    4.使用場景:這個在上條已經(jīng)說了,如果想更方便獲取HttpServletRequest的信息就使用WebRequestInterceptor,當(dāng)然這些HandlerInterceptor都能做,只不過要多寫點(diǎn)代碼

    實(shí)現(xiàn)RequestInterceptor接口

    自定義類實(shí)現(xiàn)RequestInterceptor接口,此方式為微服務(wù)Feign調(diào)用的自定義攔截器,實(shí)現(xiàn)各個微服務(wù)之間的參數(shù)傳遞。

    @Configuration
    public class CenterinsRequestInterceptor implements RequestInterceptor {
    
        @Override
        public void apply(RequestTemplate requestTemplate) {
    
        }
    }

    小插曲 @Configuration和@Component區(qū)別

    這里使用了@Configuration注解而不是@Component,其實(shí)@Configuration本質(zhì)上也是一個@Component,只不過前者描述的類中所有用@Bean標(biāo)記的方法都會由CGLIB動態(tài)代理執(zhí)行,在首次調(diào)用的時候會執(zhí)行,然后把執(zhí)行結(jié)果放到Spring上下文,之后對該方法的調(diào)用都是從Spring上下文上取的結(jié)果,所以都是指同一個實(shí)例。而使用了@Component,所有用@Bean標(biāo)記的方法都是純Java調(diào)用,每次都是生成不同的實(shí)例對象。如果要讓使用了@Compnent注解的類中其@Bean標(biāo)記的方法生成都是同一個實(shí)例,只需要使用@AutoWired標(biāo)記屬性,自動注入即可。

    @Configuration
    public class MyBeanConfig {
     
        @Bean
        public Country country(){
            return new Country();
        }
     
        @Bean
        public UserInfo userInfo(){
            return new UserInfo(country());
        }
     
    }
    
     // 以上代碼 等同于以下代碼 
     // 以下代碼去掉Autowired注入,則country方法是不同的實(shí)例對象。
     
    @Component
    public class MyBeanConfig {
     
        @Autowired
        private Country country;
     
        @Bean
        public Country country(){
            return new Country();
        }
     
        @Bean
        public UserInfo userInfo(){
            return new UserInfo(country);
        }
     
    }

    注冊攔截器

    注冊攔截器在springboot中直接使用注解便可實(shí)現(xiàn)。

    繼承WebMvcConfigurerAdapter類

     1.創(chuàng)建一個自定義類,繼承WebMvcConfigurerAdapter類重寫addInterceptors方法。

    @Configuration
    public class WebCofiguration extends WebMvcConfigurerAdapter {
        public void addInterceptors(InterceptorRegistry registry) {
        		// 將自己定義的攔截器注入進(jìn)來進(jìn)行攔截操作
            registry.addInterceptor(new MySelfInterceptor ())
                    .addPathPatterns("/**")
                    .excludePathPatterns("/logout");
                    //過濾器可以添加多個,這里的addPathPatterns的/**是對所有的請求都做攔截。
                    //excludePathPatterns代表排除url的攔截路徑,即不攔截
        }
    }

    此類在SpringBoot2.0以后已經(jīng)廢除,但仍可使用。推薦使用以下兩種方式來代替此方式。

    繼承WebMvcConfigurationSupport類

     2.創(chuàng)建一個自定義類繼承WebMvcConfigurationSupport類,實(shí)現(xiàn)addInterceptors。

    @Configuration
    public class MyInterceptorConfig extends WebMvcConfigurationSupport {
    
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
            super.addInterceptors(registry);
        }
    }

    此方式會導(dǎo)致默認(rèn)的靜態(tài)資源被攔截,這就需要我們手動將靜態(tài)資源放開。
    除了重寫方法外還需要重寫addResourceHandlers方法來釋放靜態(tài)資源

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        super.addResourceHandlers(registry);
    }

    實(shí)現(xiàn)WebMvcConfigurer接口

     3.創(chuàng)建一個自定義類實(shí)現(xiàn)WebMvcConfigurer接口,重寫addInterceptors方法。

    @Configuration
    public class MyInterceptorConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 實(shí)現(xiàn)WebMvcConfigurer不會導(dǎo)致靜態(tài)資源被攔截
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
        }
    }

    此方式不會攔截靜態(tài)資源

    應(yīng)用場景

    由于這兩種方式的不同:
    繼承 WebMvcConfigurationSupport類的方式推薦用在前后端分離的項(xiàng)目中,后臺不需要訪問靜態(tài)資源(就不需要放開靜態(tài)資源了),當(dāng)然也可以在前后端不分離中,如果需要訪問靜態(tài)資源使用上面的方式重寫addResourceHandlers方法即可;
    實(shí)現(xiàn) WebMvcConfigure接口的方式推薦用在非前后端分離的項(xiàng)目中,因?yàn)樾枰x取一些圖片、css、js文件等等,當(dāng)然也可以使用在前后端分離項(xiàng)目。

    攔截器執(zhí)行流程

    單個攔截器

    對單個攔截器執(zhí)行流程解釋如下:
    程序首先會執(zhí)行攔截器類中的preHandle()方法,如果該方法返回true,則程序會繼續(xù)向下執(zhí)行處理器中的方法,否則程序?qū)⒉辉偻吕^續(xù)執(zhí)行。在業(yè)務(wù)處理器(即控制器Controller類)處理完請求后,會執(zhí)行postHandle()方法,然后會通過DispatcherServlet向客戶端返回響應(yīng),在DispatcherServlet處理完請求后,才會執(zhí)行afterCompletion()方法。
    因此單個攔截器的執(zhí)行流程:
    prehandle()——Handle(也就是控制器里的方法)——postHandle()——afterCompletion()。

    多個攔截器

    在大型的企業(yè)級項(xiàng)目中,通常會配置多個攔截器來實(shí)現(xiàn)不同的功能。例如我們自定義了三個攔截器A、B、C。并將它們都注冊到同一個攔截器配置類中,如下圖

    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new AInterceptor())
                    .addPathPatterns("/**");
    
            registry.addInterceptor(new BInterceptor())
                    .addPathPatterns("/**");
    
            registry.addInterceptor(new CInterceptor())
                    .addPathPatterns("/**");
        }
    }

    它們的preHandle()方法會按照配置文件中攔截器的配置順序執(zhí)行,而它們的postHandle()和afterCompletion()方法則會按照配置順序的反序執(zhí)行。
    因此當(dāng)前我們的三個攔截器執(zhí)行順序如下:
    preHandleA——preHandleB——preHandleC——Handle——postHandleC——postHandleB——postHandleA——afterCompletionC——afterCompletionB——afterCompletionA

    感謝各位的閱讀,以上就是“SpringBoot攔截器如何使用”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對SpringBoot攔截器如何使用這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI