Spring Boot學習----攔截器

Spring Boot 攔截器

定義攔截器

定義攔截器,只需要實現 HandlerInterceptor 接口。該接口中有三個方法: preHandle(……)postHandle(……)afterCompletion(……)

preHandle(……) 方法:該方法的執行時機是,當某個 url 已經匹配到對應的 Controller 中的某個方法,且在這個方法執行之前。所以 preHandle(……) 方法可以決定是否將請求放行,這是通過返回值來決定的,返回 true 則放行,返回 false 則不會向後執行。
postHandle(……) 方法:該方法的執行時機是,當某個 url 已經匹配到對應的 Controller 中的某個方法,且在執行完了該方法,但是在 DispatcherServlet 視圖渲染之前。所以在這個方法中有個 ModelAndView 參數,可以在此做一些修改動作。
afterCompletion(……) 方法:顧名思義,該方法是在整個請求處理完成後(包括視圖渲染)執行,這時做一些資源的清理工作,這個方法只有在 preHandle(……) 被成功執行後並且返回 true 纔會被執行。

  • 自定義攔截器。
public class MyInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        String methodName = method.getName();
        logger.info("====攔截到方法:{}====", methodName);
        // 返回true纔會繼續執行,返回false則取消當前請求
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("執行完方法之後進執行(Controller方法調用之後),但是此時還沒進行視圖渲染");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("整個請求都處理完咯,DispatcherServlet也渲染了對應的視圖咯,此時我可以做一些清理的工作了");
    }
}

配置攔截器

在 Spring Boot 2.0 之前,我們是直接繼承 WebMvcConfigurerAdapter 類,然後重寫 addInterceptors 方法來實現攔截器的配置。但是在 Spring Boot 2.0 之後,該方法已經被廢棄了(當然,也可以繼續用),取而代之的是 WebMvcConfigurationSupport 方法,如下:

@Configuration
public class MyInterceptorConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}

在該配置中重寫 addInterceptors 方法,將我們上面自定義的攔截器添加進去,addPathPatterns 方法是添加要攔截的請求,這裏我們攔截所有的請求。這樣就配置好攔截器了,接下來寫一個 Controller 測試一下:

@Controller
@RequestMapping("/interceptor")
public class InterceptorController {

    @RequestMapping("/test")
    public String test() {
        return "hello";
    }
}

解決靜態資源被攔截問題

上文中已經介紹了攔截器的定義和配置,但是這樣是否就沒問題了呢?其實不然,如果使用上面這種配置的話,我們會發現一個缺陷,那就是靜態資源被攔截了。可以在 resources/static/ 目錄下放置一個圖片資源或者 html 文件,然後啓動項目直接訪問,即可看到無法訪問的現象。

也就是說,雖然 Spring Boot 2.0 廢棄了WebMvcConfigurerAdapter,但是 WebMvcConfigurationSupport 又會導致默認的靜態資源被攔截,這就需要我們手動將靜態資源放開。

如何放開呢?除了在 MyInterceptorConfig 配置類中重寫 addInterceptors 方法外,還需要再重寫一個方法:addResourceHandlers,將靜態資源放開:

/**
 * 用來指定靜態資源不被攔截,否則繼承WebMvcConfigurationSupport這種方式會導致靜態資源無法直接訪問
 * @param registry
 */
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    super.addResourceHandlers(registry);
}

這樣配置好之後,重啓項目,靜態資源也可以正常訪問了。如果你是個善於學習或者研究的人,那肯定不會止步於此,沒錯,上面這種方式的確能解決靜態資源無法訪問的問題,但是,還有更方便的方式來配置。

我們不繼承 WebMvcConfigurationSupport 類,直接實現 WebMvcConfigurer 接口,然後重寫 addInterceptors 方法,將自定義的攔截器添加進去即可,如下:

@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 實現WebMvcConfigurer不會導致靜態資源被攔截
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

這樣就非常方便了,實現 WebMvcConfigure 接口的話,不會攔截 Spring Boot 默認的靜態資源。

這兩種方式都可以,具體他們之間的細節,感興趣的讀者可以做進一步的研究,由於這兩種方式的不同,繼承 WebMvcConfigurationSupport 類的方式可以用在前後端分離的項目中,後臺不需要訪問靜態資源(就不需要放開靜態資源了);實現 WebMvcConfigure 接口的方式可以用在非前後端分離的項目中,因爲需要讀取一些圖片、css、js文件等等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章