過濾器和監聽器總結
阿新 • • 發佈:2020-11-13
[toc]
## 一、過濾器 Filter
### 1. 什麼是過濾器?
過濾期正如我們生活中用來過濾東西的東西,泡茶喝,用紗網過濾茶葉一樣。再web中,當我們瀏覽器訪問伺服器時候,瀏覽器所傳送的請求會先經過過濾器被攔截下來,讓過濾器來執行某些操作。在實際開發中,過濾器的常用用途有**登入驗證**、**統一編碼處理**、**過濾敏感字元**等等
### 2. 入門
要建立一個過濾器,只需要建立一個Java類,然後讓過濾器實現Filter介面,然後重寫裡面的三個方法:**init**、**doFilter**、**destroy**即可,最後再配置一下攔截路徑即可。
首先,對於inti、destroy方法,他和servlet是一樣的,在伺服器載入和銷燬的時候會執行一次,通常inti用來**載入資源**,而伺服器在正常關閉後,Filter物件被銷燬,只執行一次destroy方法,用於**釋放資源**
對於doFilter,他是在每次請求攔截資源時候,都會執行,所以他是執行多次的。要注意,該方法有三個引數,前兩個我們都很熟悉了,對於第三個引數FilterChain,他是一個介面,在該介面中又定義了doFilter方法。這是咋回事呢?可以這樣理解:**過濾器不單隻有一個,在Java中就使用了鏈式結構。把所有的過濾器都放在FilterChain裡邊,如果符合條件,就執行下一個過濾器(如果沒有過濾器了,就執行目標資源)**。
### 3. 執行流程
1. 先執行過濾器
2. 執行放行後的資源
3. 最後再返回回來執行放行程式碼下面的其他程式碼
### 4. 配置攔截路徑
#### 4.1 註解配置方法
若要使用註解方法配置攔截路徑,需要在Filter前面加上`@WebFilter()`括號裡面的就是攔截路徑,如果只寫攔截路徑,可以不寫引數名,因為預設就是`value/urlPattern`,如果還要設定其他引數的話,那麼就要加上引數名了。如果想要部分的Web資源進行過濾器過濾則需要指定Web資源的名稱即可。
若要指定**過濾器攔截的資源被Servlet容器呼叫的方式**,那麼可以設定`dispatcherTypes`,有:DispatcherType.REQUEST(預設)、DispatcherType.ERROR、DispatcherType.FROWARD、DispatcherType.INCLUDE、DispatcherType.ASYNC五種方式,分別對應如下:
- REQUEST:預設值。瀏覽器直接請求資源
- FORWARD:轉發訪問資源
- INCLUDE:包含訪問資源
- ERROR:錯誤跳轉資源
- ASYNC:非同步訪問資源
#### 4.2web.xml配置方法
在web.xml中,新增如下程式碼:**filter用於註冊過濾器,如果沒有配置的話,即使實現類Filter介面也沒有用**
```xml
設定一個filter名
要配置的Filter的全類名
word_file
/WEB-INF/word.txt
對應上面的filter名
設定攔截路徑
?指定 Filter 對資源的多種呼叫方式進行攔截(預設REQUEST)
過濾指定的servlet的資源名稱
```
### 5. 多個過濾器(過濾器鏈)的執行順序
- 過濾器1
- 過濾器2
- 過濾器3
- 執行目標資源
- 過濾器3的剩下的程式碼
- 過濾器2的剩下的程式碼
- 過濾器1的剩下的程式碼
**過濾器的先後執行順序問題是怎樣的?**
1. 如果使用的是web.xml配置的話,那麼你的``filter-mapping`哪個寫在前面就會先執行哪個過濾器,寫在後面的就會後執行,和filter無關。
2. 如果使用的是註解的配置方式的話,那麼會比較**過濾器的類名**,值小的先執行,例如a小於b,所以a過濾器會先執行
### 6. 過濾器的簡單應用
#### 6.1 禁止瀏覽器快取
```java
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
// 只有HttpServletResponse才可以設定響應資訊,所以我們一般都將他們轉化為Http
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// 設定禁止快取
response.setDateHeader("Expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
chain.doFilter(request, response);
}
```
設定之後響應頭為:
![](https://img2020.cnblogs.com/blog/2067154/202011/2067154-20201109132136511-594929067.png)
#### 6.2 實現自動登入
#### 6.3 編碼過濾器
- 可以通過實現HTTP ServletRequestWrapper類來增強request物件
#### 6.4 敏感詞彙過濾
- 可以使用動態代理實現敏感詞彙過濾
#### 6.5 壓縮資源過濾器
#### 6.6 HTML轉義過濾器
#### 6.7 快取資料到記憶體中
## 二、監聽器 Listener
### **什麼是監聽器?**
監聽器就是⼀個實現特定接⼝的普通java程式,這個程式專⻔⽤於監聽另⼀個java物件的⽅法調
⽤或屬性改變,當被監聽物件發⽣上述事件後,監聽器某個⽅法將⽴即被執⾏。
### 事件監聽機制
- 事件源:事件發生的物件,即被監聽的物件
- 事件物件:封裝事件源和動作
- 事件監聽器:將事件物件傳入,由開發人員編寫監聽器物件處理事件物件
- 註冊監聽:在事件源上關聯監聽器物件
![](https://img2020.cnblogs.com/blog/2067154/202011/2067154-20201112182009957-962685618.png)
### 內建監聽器
在Servlet規範中定義了多種型別的監聽器,它們⽤於監聽的事件源分別 ServletContext,HttpSession和ServletRequest 這三個域物件
Servlet監聽器的註冊不是在事件源上,而是由web容器負責,我們只需要在web.xml中配置好標籤即可
#### 監聽物件的建立和銷燬
**HttpSessionListener、ServletContextListener、ServletRequestListener**分別監聽著Session、Context、Request物件的建立和銷燬
- HttpSessionListener(可以⽤來收集線上者資訊)
- ServletContextListener(可以獲取web.xml⾥⾯的引數配置)
- ServletRequestListener
#### 監聽物件屬性的變化
ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener 分別監聽著Context、Session、Request物件屬性的變化
著三個介面都定義了以以下三個方法來處理被監聽物件中的屬性的增加、刪除、替換事件,同一個事件在三個介面中方法名完全相同,只是接受的引數型別不同:
- attributeAdded()
- attributeRemoved()
- attributeReplaced()
#### 監聽Session內的物件
除了上面的6中listener,還有兩種listener監聽Session的物件:HttpSessionBindingListerner和HttpSsessionActivation:
- HttpSessionBindingListener: JavaBean物件可以感知自己被繫結到Session中和從Session中的刪除的事件( 和HttpSessionAttributeListener的作用是差不多的 )
- HttpSessionActivationListener: JavaBend物件可以感知自己被活化和鈍化的事件( 當伺服器關閉時, 會將Session的內容儲存在硬碟上**[鈍化]**, 當伺服器開啟時, 會將Session的內容在硬碟上重新載入**[活化]** )
想要測試出Session的硬化和鈍化,需要修改Tomcat的配置的。在META-INF下的context.xml⽂件中新增下⾯的程式碼:
```xml
```
### 監聽器的應用
- 統計網站線上人數
- 監聽Session是否被建立了
- 如果Session建立了, Context域物件的人數的值就+1
- 如果Session被移除了, 那麼值就-1
- 自定義Session掃描器
- 監聽Session和Context的建立
- 使用一個容器來裝Session
- 定時掃描容器中的Session,如果長時間沒用就remove
- 線上踢人
- 也是使用容器來裝Session
- 列出所用使用者
- 可以選擇將列出使用者(Session)踢掉, 即刪除Session