什么是Filter過濾器灰羽?
Filter在Web開發(fā)中通常被稱為過濾器技矮,是一種用于攔截處理請求和響應的組件肢扯。它可以在請求到達目標資源之前進行攔截导梆,也可以對響應進行攔截。通過使用過濾器料按,可以對請求參數(shù)進行校驗、對響應內(nèi)容進行壓縮和加密等操作,從而提高系統(tǒng)的安全性婆殿、性能和可靠性。
過濾器可以串聯(lián)在處理請求的整個路徑中罩扇,對請求進行預處理和后處理婆芦。例如,可以過濾掉惡意請求喂饥、對請求參數(shù)進行統(tǒng)一格式化等消约。在處理響應時,可以統(tǒng)一設置響應頭员帮、對響應內(nèi)容進行壓縮等或粮。
- Filter 過濾器它是 JavaWeb 的三大組件之一。
- Filter 過濾器它是 JavaEE 的規(guī)范捞高。也就是接口
- Servlet3.0可以用注解@WebFilter氯材,Servlet2.5可以使用xml文件配置。
- Filter在配置時棠枉,和servlet一樣浓体,也可以配置通配符,例如 @WebFilter("*.do")表示攔截所有以.do結(jié)尾的請求
攔截請求常見的應用場景有: 1辈讶、權限檢查 2命浴、日記操作 3、事務管理 ……等等。
假設有一個admin目錄生闲,使用用戶登錄之后才可以訪問這個目錄下的資源媳溺。
思考:
我們知道,用戶登錄之后都會把用戶登錄的信息保存到 Session 域中碍讯。所以要檢查用戶是否登錄悬蔽,可以判斷 Session 中否包含有用戶登錄的信息即可!
<body>
<%
Object user = session.getAttribute("user");
// 如果等于 null捉兴,說明還沒有登錄
if (user == null) {
request.getRequestDispatcher("/login.jsp").forward(request,response);
return;
}
%>
<h2>這是info.jsp</h2>
</body>
結(jié)論:
這種在jsp頁面方式雖然能判斷用戶是否登錄限制資源訪問蝎困,但如果在html頁面下無法使用這種判斷方式,有了局限性倍啥,所以最好是使用Filte過濾器限制訪問禾乘。
Filter工作流程
Filter案例實操
Filter 過濾器的使用步驟:
1、編寫一個類去實現(xiàn) Filter 接口
2虽缕、實現(xiàn)過濾方法 doFilter()
3始藕、到 web.xml 中去配置 Filter 的攔截路徑
<body>
這是登錄頁面。login.jsp 頁面 <br>
<form action="http://localhost:8080/day05_cookie/login" method="get">
用戶名:<input type="text" name="username"/> <br>
密 碼:<input type="password" name="password"/> <br>
<input type="submit" />
</form>
</body>
public class AdminFilter implements Filter {
public AdminFilter() {
System.out.println("Filter實現(xiàn)類的構造器初始化操作...");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter過濾器初始化操作...");
}
/**
* doFilter():專門用于攔截請求氮趋,過濾響應
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
var httpServletRequest = (HttpServletRequest) servletRequest;
var session = httpServletRequest.getSession();
var user = session.getAttribute("user");
if (user == null) {
//如果等于null,則沒有登錄成功
servletRequest.getRequestDispatcher(File.separator + "login.jsp").forward(servletRequest,servletResponse);
} else {
//登錄成功伍派,放行當前請求和響應
filterChain.doFilter(servletRequest,servletResponse);
}
}
@Override
public void destroy() {
System.out.println("Filter過濾器銷毀操作...");
}
}
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
var username = req.getAttribute("username");
var password= req.getAttribute("password");
if ("admin".equals(username) && "123456".equals(password)) {
req.getSession().setAttribute("user",username);
resp.getWriter().write("登錄成功");
} else {
req.getRequestDispatcher(File.separatorChar + "login.jsp").forward(req,resp);
}
}
}
<!-- 配置Filter過濾器 -->
<filter>
<!-- Filter實現(xiàn)類的別名 -->
<filter-name>adminFilter</filter-name>
<!-- Filter實現(xiàn)類的全類名 -->
<filter-class>com.evan.java.AdminFilter</filter-class>
</filter>
<!-- 映射當前請求到Filter實現(xiàn)類 -->
<filter-mapping>
<!-- 當前請求的攔截路徑到哪個Filter使用 -->
<filter-name>adminFilter</filter-name>
<!-- 配置攔截路徑:
/ 表示請求地址是 http://ip:port/工程路徑/ 映射到當前工程模塊的web目錄
/admin/* 表示請求地址是 http:ip:port/工程路徑/admin/*
-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
<!-- 配置servlet訪問 -->
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>com.evan.java.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
結(jié)論:
當login.jsp登錄成功時當前請求執(zhí)行目標資源,F(xiàn)ilter檢查滿足規(guī)則則會放行剩胁,繼續(xù)執(zhí)行下一個操作诉植;當?shù)卿浭∪?zhí)行當前請求的目標資源時會被攔截跳轉(zhuǎn)到login.jsp
Filter生命周期
public class AdminFilter implements Filter {
public AdminFilter() {
System.out.println("1.Filter實現(xiàn)類的構造器初始化操作...");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("2.Filter過濾器初始化操作...");
}
/**
* doFilter():專門用于攔截請求,過濾響應
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("3.doFilter執(zhí)行請求和響應的攔截操作...");
}
@Override
public void destroy() {
System.out.println("4.Filter過濾器銷毀操作...");
}
}
Filter聲明周期的執(zhí)行過程:
- 執(zhí)行FIlter實現(xiàn)類的構造器
- 執(zhí)行Filter初始化方法
- 執(zhí)行Filter的doFilter攔截方法
- 執(zhí)行FIlter的銷毀方法
步驟1和2是在web工程啟動時執(zhí)行昵观,后續(xù)web工程沒有關閉倍踪,再次執(zhí)行Filter操作會執(zhí)行步驟3,步驟3在每次攔截到請求時執(zhí)行索昂,步驟4在工程停止時執(zhí)行。
FilterConfig類
FilterConfig 類見名知義扩借,它是 Filter 過濾器的配置文件類椒惨。
Tomcat 每次創(chuàng)建 Filter對象的時候,也會同時創(chuàng)建一個 FilterConfig 類潮罪,這里包含了 Filter 配置文件的配置信息康谆。
FilterConfig 類的作用是獲取 filter 過濾器的配置內(nèi)容 :
1、獲取 Filter 的名稱 filter-name 的內(nèi)容
2嫉到、獲取在 Filter 中配置的 init-param 初始化參數(shù)
3沃暗、獲取 ServletContext 對象
public class AdminFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter過濾器初始化操作...");
//獲取Filter的名稱filter-name的內(nèi)容
System.out.println("filter-name值:" + filterConfig.getFilterName());
//獲取web.xml中配置的init-param初始化參數(shù)
System.out.println("初始化參數(shù)username的值是:" + filterConfig.getInitParameter("username"));
//獲取ServletContext對象
System.out.println("ServletContext對象:" + filterConfig.getServletContext());
}
}
<!-- 配置Filter過濾器 -->
<filter>
<!-- Filter實現(xiàn)類的別名 -->
<filter-name>adminFilter</filter-name>
<!-- Filter實現(xiàn)類的全類名 -->
<filter-class>com.evan.java.AdminFilter</filter-class>
<!-- 配置Filter初始化參數(shù)值 -->
<init-param>
<param-name>username</param-name>
<param-value>admin</param-value>
</init-param>
</filter>
<!-- 映射當前請求到Filter實現(xiàn)類 -->
<filter-mapping>
<!-- 當前請求的攔截路徑到哪個Filter使用 -->
<filter-name>adminFilter</filter-name>
<!-- 配置攔截路徑:
/ 表示請求地址是 http://ip:port/工程路徑/ 映射到當前工程模塊的web目錄
/admin/* 表示請求地址是 http:ip:port/工程路徑/admin/* 映射到當前工程模塊的web目錄下的admin目錄
-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
FilterChain 過濾器鏈
Filter: 過濾器 。
Chain :鏈何恶,鏈條孽锥。
FilterChain就是過濾器鏈條。
多個FilterChain執(zhí)行的特點:
1、所有Filter和目標資源默認都執(zhí)行在同一個線程中惜辑。
2唬涧、多個Filter共同執(zhí)行的時候,它們都使用同一個Request對象盛撑。
FilterChain.doFilter方法的作用:
1碎节、執(zhí)行下一個Filter過濾器(如果有Filter)
2、執(zhí)行目標資源(下一步?jīng)]有Filter執(zhí)行目標資源)
在多個Filter過濾器執(zhí)行的時候抵卫,他們執(zhí)行的優(yōu)先順序是由他們在web.xml中配置從上而下的順序決定狮荔。
案例實操
//Filter1實現(xiàn)類
public class Filter1 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter1 前置代碼");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("Filter1 后置代碼");
}
}
//Filter2實現(xiàn)類
public class Filter2 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter2 前置代碼");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("Filter2 后置代碼");
}
}
<filter>
<filter-name>filter1</filter-name>
<filter-class>com.evan.java.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>/filterTest.jsp</url-pattern>
</filter-mapping>
<filter>
<filter-name>filter2</filter-name>
<filter-class>com.evan.java.Filter2</filter-class>
</filter>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern>/filterTest.jsp</url-pattern>
</filter-mapping>
FilterChain的執(zhí)行結(jié)果:
Filter1 前置代碼
Filter1的線程:http-nio-8080-exec-3
Filter2 前置代碼
Filter2的線程:http-nio-8080-exec-3
filterText.jsp
Filter2 后置代碼
Filter1 后置代碼
FIilterChain的執(zhí)行順序:
先執(zhí)行Filter鏈的所有前置代碼以及doFIlter的攔截方法,然后執(zhí)行Filter鏈的所有后置代碼介粘;同時它們的都是在一個線程中按照web.xml中的filter配置的先后順序執(zhí)行殖氏。
如果采取的是注解的方式進行配置,那么過濾器鏈的攔截順序是按照全類名的先后順序排序的碗短。
如果采取的是xml的方式進行配置受葛,那么按照配置的先后順序進行排序。
Filter 的攔截路徑
- 精確匹配
<url-pattern>/target.jsp</url-pattern>
以上配置的路徑偎谁,表示請求地址必須為:http://ip:port/工程路徑/target.jsp
- 目錄匹配
<url-pattern>/admin/*</url-pattern>
以上配置的路徑总滩,表示請求地址必須為:http://ip:port/工程路徑/admin/*
- 后綴名匹配
<url-pattern>*.html</url-pattern>
以上配置的路徑,表示請求地址必須以.html 結(jié)尾才會攔截到
<url-pattern>*.do</url-pattern>
以上配置的路徑巡雨,表示請求地址必須以.do 結(jié)尾才會攔截到
<url-pattern>*.action</url-pattern>
以上配置的路徑闰渔,表示請求地址必須以.action 結(jié)尾才會攔截到
結(jié)論:
Filter 過濾器它只關心請求的地址是否匹配,不關心請求的資源是否存在n硗8越А!