過濾器
作用
實現對web資源請求的攔截,完成特殊的操作,尤其是對請求的預處理。
應用場景
- Web資源權限訪問控制
- 字符集編碼處理
- 內容敏感字符詞彙過濾
- 響應信息壓縮
工作流程
過濾器的生命週期
- 過濾器的創建和銷燬由web服務器負責
- web應用程序啓動時,web服務器創建Filter的實例對象 ,以及對象的初始化。(調用
init()
方法,這個方法只在tomcat服務器啓動的時候調用一次) - 當請求訪問與過濾器關聯的web資源時(某個URL),過濾器攔截請求,完成指定功能(完成後交給下一個過濾器或者servlet進行處理)。(調用
doFilter()
方法,web程序運行期間可多次調用) - Filter對象創建後會一直駐留在內存中,在web應用移除或服務器停止時才銷燬。(調用
destory()
方法)
過濾器鏈
-
在一個web應用中,多個過濾器組合起來稱之爲一個過濾器鏈。(比如說有的請求不止需要被一個過濾器攔截進行處理[先是字符集編碼的處理的過濾器,再是判斷是否登錄的過濾器],這時就需要編寫多個過濾器類來分別處理)
-
過濾器請求預處理的調用順序取決於過濾器在web.xml文件中的註冊順序,而過濾器響應後處理的調用順序取決於過濾器註冊順序的逆序。
(web.xml的順序決定的是執行
doFilter()
的順序 並不決定init()
的順序)
過濾器的實現步驟
編寫java類實現Filter接口
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
//要實現javax.servlet.Filter接口,重寫下面三個方法
public class CharacterEncodingFilter implements Filter {
@Override
public void destroy() {
//在過濾器銷燬的時候做一些清理工作
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//完成過濾器的功能
//request是請求預處理
//reponse是響應後處理
//不要忘記調用這個方法,意思是交給下一個過濾器或者servlet(請求本來要到達的地方)進行後續的操作處理
chain.doFilter(request,response);
}
@Override
public void init(FilterConfig config) throws ServletException {
this.config = config;
//在過濾器對象創建的時候做一些初始化操作
//參數中FilterConfig是過濾器配置類,在配置Filter的時候會設置一些初始化參數(設置初始化參數都是在web.xml文件中或者註解中完成),把這些配置封裝成配置類對象傳入進來
/*在web.xml中
<filter>
.....註冊filter
<init-param>
<param-name>version</param-name>
<param-value>2.0</param-value>
</init-param>
</filter>
*/
/*
在init()函數中
通過 config.getInitParameter("version");能獲取version的值
*/
}
}
在web.xml文件中對filter類進行註冊,並設置所攔截的資源
<!-- 註冊過濾器,讓web服務器識別到這個過濾器要對一些web請求做攔截處理-->
<filter>
<filter-name>TestFilter</filter-name>
<filter-class>com.lxc.TestFilter</filter-class>
<!--設置過濾器配置類的初始化參數 -->
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!--攔截映射的配置,指定過濾器對哪些請求做攔截處理 -->
<!-- /*代表所有的請求都會被這個過濾器攔截 -->
<filter-mapping>
<filter-name>TestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置要攔截的資源
-
以指定資源匹配。例如
"/index.jsp"
-
以目錄匹配。例如
"/servlet/*"
-
以後綴名匹配,例如
"*.jsp"
-
通配符,攔截所有web資源。
"/*"
-
攔截多個頁面
<filter> <filter-name>authority</filter-name> <filter-class>com.util.AuthorityFilter</filter-class> </filter> <filter-mapping> <filter-name>authority</filter-name> <url-pattern>/pages/genbill/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>authority</filter-name> <url-pattern>/pages/cmm/*</url-pattern> </filter-mapping>
filter-mapping的子元素dispather
必須寫在filter-mapping的最後。dispatcher的前提條件當然是要先滿足url-pattern
,然後是dispatcher屬性。
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/test2.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
如果不寫dispatcher
這個子屬性,那麼默認是REQUEST
dispatcher有四種可能的屬性:
1、REQUEST
只要發起的操作是一次HTTP請求,比如請求某個URL、發起了一個GET請求、表單提交方式爲POST的POST請求、表單提交方式爲GET的GET請求。一次重定向則前後相當於發起了兩次請求,這些情況下有幾次請求就會走幾次指定過濾器。
2、FOWARD
只有噹噹前頁面是通過請求轉發轉發過來的情形時,纔會走指定的過濾器 (但該過濾器必須指定了<dispatcher>FORWARD</dispatcher>
)
3、INCLUDE
只要是通過<jsp:include page="xxx.jsp" />
,嵌入進來的頁面,每嵌入的一個頁面,都會走一次指定的過濾器。
4、ERROR
假如web.xml裏面配置了<error-page></error-page>
<error-page>
<error-code>400</error-code>
<location>/filter/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/filter/error.jsp</location>
</error-page>
不管這個請求是從哪裏發過來的(
jsp
還是過濾器),發送方是什麼方式就按什麼方式匹配。
也可以把四種可能都寫上,四種情況都會攔截
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/test2.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
使用註解配置Filter
@WebFilter(filterName = "CharsetFilter",
urlPatterns = { "/AddServlet","/qiantai/order.jsp","/RemoveServlet", "/UserOrderingServlet" },
dispatcherTypes = {DispatcherType.ASYNC,DispatcherType.ERROR},/*枚舉類型*/
initParams = {
@WebInitParam(name = "charset", value = "utf-8"),/*這裏可以放一些初始化的參數*/ @WebInitParam(name = "contenttype", value = "text/html;charset=utf-8")
})
使用註解配置的話,filter的執行順序(過濾器類doFilter()
方法的執行順序)跟過濾器類的類名的字母順序有關,例如AFilter.java
會比BFilter.java
先執行
請求和響應字符集編碼處理
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class CharacterEncodingFilter implements Filter {
//接收過濾配置類對象
private FilterConfig config;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//不直接設置爲UTF-8,而是把編碼的信息放在web.xml文件中,以後直接修改web.xml中的初始化參數就行,避免了java代碼的重新編譯等操作
// 根據過濾器配置字符集,設置請求字符集編碼
request.setCharacterEncoding(config.getInitParameter("charset"));
response.setContentType(config.getInitParameter("responsecharset"));
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
}
web.xml文件
<!-- 字符集編碼過濾器配置 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>responsecharset</param-name>
<param-value>text/html;charset=utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
登錄驗證
使用註解配置過濾器,攔截的時候不能攔截全部頁面,不然會出現很多後續的麻煩
@WebFilter(filterName = "LoginFilter", urlPatterns = "*.jsp", dispatcherTypes = {})
public class SessionFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest hrequest = (HttpServletRequest)request;
HttpServletResponse hresponse = (HttpServletResponse)response;
String loginUser = (String)hrequest.getSession().getAttribute("loginUser");//從session對象中獲取登錄用戶名
if(loginUser==null){//登錄用戶名不存在,用戶未登錄,強制重定向至登陸頁面
hresponse.sendRedirect(hrequest.getContextPath()+"/index.jsp?flag=1");
return;
}else{
chain.doFilter(request, response);//已登錄,轉入相應的請求處理
return;
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}