Note | 在WebMvcConfiguration介面中配置過濾器(Filter)

2022 MAR 5

問題

課題中用到兩個過濾器,一個是用於輸出日誌到文本文件的LoggingFilter,另一個是用於檢查請求中是否有合規的Bearer Token的TokenFilter

簡單寫一下兩個過濾器的定義:

javaCopied!
//TokenFilter.java @Component @RequiredArgsConstructor public class TokenFilter extends OncePerRequestFilter { private final TokenService tokenService; private final ObjectMapper objectMapper; private final MessageSource messageSource; @Override protected void doFilterInternal() {/*...*/} }
javaCopied!
//LoggingFilter.java @Component public class LoggingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal() {/*...*/} }

在之前,路徑匹配是直接定義在doFilterInternal()方法中的:

javaCopied!
if (httpServletRequest.getRequestURI().equals(/*requested url */)) {/*...*/}

為了簡化程序,需要把這兩個過濾器的路徑匹配轉移到WebMvcConfiguration介面中完成。

解決

用Lombok的@RequiredArgsConstructor註解在WebMvcConfiguration類中直接聲明兩個過濾器:

javaCopied!
//WebMvcConfig.java @Configuration @RequiredArgsConstructor public class WebMvcConfig implements WebMvcConfigurer { private final LoggingFilter loggingFilter; private final TokenFilter tokenFilter; //... }

這樣在註冊過濾器的時候就不再需要用構造函數來創建實例了。

之後註冊新的過濾器(有兩個過濾器,所以需要寫兩個方法,這裡只展示一個)。

javaCopied!
//WebMvcConfig.java @Bean FilterRegistrationBean<LoggingFilter> loggingFilterRegistration() { FilterRegistrationBean<LoggingFilter> filterRegistrationBean = new FilterRegistrationBean<>(loggingFilter); filterRegistrationBean.addUrlPatterns("/api/products", "/api/products/*"); filterRegistrationBean.setName("Logging Filter"); filterRegistrationBean.setOrder(1); return filterRegistrationBean; }

有幾個需要注意的地方:

  1. 由於泛型的關係,如果只寫FilterRegistrationBean<>或是直接寫FilterRegistrationBean會被編譯器認為是不安全的行為,不能通過編譯;
  2. 幾個過濾器可以通過filterRegistrationBean.setOrder(/*number*/)來設定過濾器的發動順序,數字越小越優先,同時可以用Ordered.HIGHEST_PRECEDENCEOrdered.LOWEST_PRECEDENCE來設置為最優先和最不優先(實質就是Integer可取範圍的最小值和最大值)。