初探 Servlet Filter

初探 Servlet Filter

Servlet Filter Banner
Filter (過濾器)

先來看幾個最簡單的 Filter 吧!

// AllPatternFilter.java
@WebFilter("/*")
public class AllPatternFilter extends HttpFilter {
    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        System.out.println("任何 Servlet 請求都會經過我");
        chain.doFilter(req, res); // 記得 FilterChain 的 doFilter() 方法要呼叫,才會往下走
    }
}
// HelloWorldFilter.java
@WebFilter(
    urlPatterns = {"/hello-world"}
)
public class HelloWorldFilter extends HttpFilter {
    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        System.out.println("/hello-world 的請求都會經過我");
        chain.doFilter(req, res); // 記得 FilterChain 的 doFilter() 方法要呼叫,才會往下走
    }
}

Filter 過濾器的使用其實跟 Servlet 很像, 粗淺瞭解它的話 一樣是繼承 一個類別、覆寫掉方法、定義 urlPattern ... 我也是這樣瞭解的,不過就是有些細節要注意就是

首先!基本的 @WebFilter() 的設定請幫我看 「Servlet 使用教戰守則 – Annotation 篇」 的 @WebFilter 片段

透過 @WebFilter() 我們可以定義我們 Filter 的 Filter 名稱、url 匹配規則 等等的... 很豐富,我們之後的文章會詳細介紹到 我們在最一開始只要會用 urlPatterns 就好了

可以看到第一個寫的是 /* 這就代表我們任何的請求都會經過 AllPatternFilter.java 這層 Filter

而第二個是 /hello-world 這也就是指定 /hello-world 這個 url 會經過 HelloWorldFilter.java 這層 Filter

而且實際上 /hello-world 是會經過 HelloWorldFilter.java 跟 AllPatternFilter.java 這兩層 Filter 的 順序是這樣的

// /hello-world 的請求都會經過我
// 任何 Servlet 請求都會經過我

如果要能夠客製化順序的話,目前我找到的解決方法只有使用 web.xml 來定義了! 可能匹配規則就不能完全用 Annotation 來寫了這樣

這一篇比較亂一點... 就先附上目錄結構吧!

├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── judysocute
│   │   │           ├── AllPatternFilter.java
│   │   │           ├── HelloWorld.java
│   │   │           └── HelloWorldFilter.java
│   │   ├── resources
│   │   └── webapp
│   │       └── WEB-INF
│   │           └── web.xml

我們先把我們 Filter 的 Annotation 都拿掉

// AllPatternFilter.java
public class AllPatternFilter extends HttpFilter {
    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        System.out.println("任何 Servlet 請求都會經過我");
        chain.doFilter(req, res); // 記得 FilterChain 的 doFilter() 方法要呼叫,才會往下走
    }
}
// HelloWorldFilter.java
@WebFilter(
    urlPatterns = {"/hello-world"}
)
public class HelloWorldFilter extends HttpFilter {
    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        System.out.println("/hello-world 的請求都會經過我");
        chain.doFilter(req, res); // 記得 FilterChain 的 doFilter() 方法要呼叫,才會往下走
    }
}

只留這樣,再來在 web.xml 定義內容

<!--  web.xml  -->
<web-app version="4.0"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
    <filter>
        <filter-name>AllPattern</filter-name>
        <filter-class>com.judysocute.AllPatternFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AllPattern</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>HelloWorld</filter-name>
        <filter-class>com.judysocute.HelloWorldFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HelloWorld</filter-name>
        <url-pattern>/hello-world</url-pattern>
    </filter-mapping>
</web-app>

Filter 的先後順序會依據 web.xml 內定義的順序