1. 程式人生 > >Filter過濾器使用

Filter過濾器使用

Servlet中的過濾器Filter是實現了javax.servlet.Filter介面的伺服器端程式,主要的用途是過濾字元編碼、做一些業務邏輯判斷等。其工作原理是,只要你在web.xml檔案配置好要攔截的客戶端請求,它都會幫你攔截到請求,此時你就可以對請求或響應(Request、Response)統一設定編碼,簡化操作;同時還可進行邏輯判斷,如使用者是否已經登陸、有沒有許可權訪問該頁面等等工作。它是隨你的web應用啟動而啟動的,只初始化一次,以後就可以攔截相關請求,只有當你的web應用停止或重新部署的時候才銷燬。

簡單來說,過濾器filter的作用,它就相當於公路上的一個關卡,對要通過的攔截下來進行相關操作或放行。

dofilter作用【request -> filter1 -> filter2 ->filter3 -> …. -> request resource。】

看一個簡單的沒有filter的登入例子,當用戶名和密碼都是admin時,能跳轉到success頁面,否則到fail頁面。

1、eclipse建立一個web project ,結果目錄如下
這裡寫圖片描述
其中,jsp很簡單。在login.jsp為一個form表單

1   <form action="<%=request.getContextPath() %>/servlet/LoginServlet"
method="post"> 2 使用者名稱:<input type="text" name="username"> 3 密碼:<input type="password" name="password"> 4 <input type="submit" value="提交"> 5 </form>

配置檔案xml中為

 1 <servlet>
 2     <description>This is the description of my J2EE component</description>
 3
<display-name>This is the display name of my J2EE component</display-name> 4 <servlet-name>LoginServlet</servlet-name> 5 <servlet-class>com.imooc.serlvet.LoginServlet</servlet-class> 6 </servlet> 7 8 <servlet-mapping> 9 <servlet-name>LoginServlet</servlet-name> 10 <url-pattern>/servlet/LoginServlet</url-pattern> 11 </servlet-mapping>

LoginServlet.java中主要是

1     public void destroy() {
 2         super.destroy(); // Just puts "destroy" string in log
 3         // Put your code here
 4     }
 5 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 6         String username = request.getParameter("username");
 7         String password = request.getParameter("password");
 8         
 9         System.out.println(username);
10         
11         if("admin".equals(username) && "admin".equals(password)){
12             //校驗通過
13             HttpSession session = request.getSession();
14             session.setAttribute("username", username);
15             response.sendRedirect(request.getContextPath()+"/sucess.jsp");
16         }else{
17             //校驗失敗
18             response.sendRedirect(request.getContextPath()+"/fail.jsp");
19         }
20         
21     }
22 public void init() throws ServletException {
23         // Put your code here
24     }

執行後瀏覽器位址列進入:…8080/LoginFilter/login.jsp

當用戶名和密碼都輸入admin,按下submit,就會進入action對應的servlet,然後重定向到success.jsp頁面;使用者名稱密碼不對就到fail.jsp。

小例子結束。

仔細想會想到,可以直接在地址輸入8080/LoginFilter/success.jsp不就進入了成功的頁面了嗎,還有類似頁面。這樣時不安全的,所以要加入攔截器

2、在此專案加入攔截器filter,也就是對其url進行攔截,不讓其用url隨便訪問,結構中多了個類檔案
這裡寫圖片描述

在xml中新增

 1  <filter>
 2        <filter-name>LoginFilter</filter-name>
 3        <filter-class>com.imooc.filter.LoginFilter</filter-class>
 4  </filter>
 5  <filter-mapping>
 6        <filter-name>LoginFilter</filter-name>
 7        <url-pattern>/success.jsp</url-pattern>
 8  </filter-mapping>

這樣,url輸入…8080/LoginFilter/success.jsp就會進行攔截,進入LoginFilter.java

裡面主要為:

 1   @Override
 2       public void destroy() {
 3   System.out.println("銷燬...");  
 4       }
 5       @Override
 6       public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
 7           HttpServletRequest request = (HttpServletRequest) arg0;
 8           HttpServletResponse response = (HttpServletResponse) arg1;
 9           HttpSession session = request.getSession();
10   //因為登入後儲存了username,所以可以先檢查username判斷是否登入
11  if(session.getAttribute("username")!=null){
12              arg2.doFilter(arg0, arg1);//已登入,則放行,
13          }else{
14              response.sendRedirect("login.jsp");//未登入,重定向到登入頁面
15          }
16      }
17 public void init(FilterConfig arg0) throws ServletException  
18   {  
19 
20      System.out.println("初始化...");  
21 
22     }  

【過濾器Filter生命週期:init()->doFilter()->destroy()】

【 出現了 arg.doFailter(arg0,arg1),他表示好像放行、通過這樣,繼續往下到LoginServlet.java中,如果沒有寫 arg.doFailter(arg0,arg1)。那就是,把他攔截下來後,什麼都不做,也不讓它通過,那就會卡在那裡不能往下了。】

【在這裡只是request -> filter1 -> request resource。】

這樣的思路,就可以攔截一些不能隨便訪問的頁面,但如果這類頁面很多,可訪問的頁面相對少,則可以把攔截的地址改為/*,也就是

1    <filter-mapping>
2          <filter-name>LoginFilter</filter-name>
3          <url-pattern>/success.jsp</url-pattern>
4    </filter-mapping>
5 改成  
6  <filter-mapping>
7          <filter-name>LoginFilter</filter-name>
8          <url-pattern>/*</url-pattern>
9    </filter-mapping>

再對本不用攔截的,比如login.jsp 在LoginFilter進行判斷

 1      public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
 2          HttpServletRequest request = (HttpServletRequest) arg0;
 3          HttpServletResponse response = (HttpServletResponse) arg1;
 4         HttpSession session = request.getSession();
 5 //如果是login.jsp,則不攔截,直接放行,不用進行其他操作
 6 if(request.getRequestURI().indexOf("login.jsp")!=-1 ){
 7                     arg2.doFilter(arg0, arg1);
 8                     return;
 9                 }
10 
11 //因為登入後儲存了username,所以可以先檢查username判斷是否登入
12  if(session.getAttribute("username")!=null){
13              arg2.doFilter(arg0, arg1);//已登入,則放行,
14          }else{
15              response.sendRedirect("login.jsp");//未登入,重定向到登入頁面
16          }

仔細想想,其他問題也來了,因為攔截所有頁面,所以按下submit時都過不去(action=”<%=request.getContextPath() %>/servlet/LoginServlet” 也要攔截,過不去),則要新增一些不需攔截的url
複製程式碼

1 //如果是下面3個url,則不攔截,直接放行,不用進行其他操作
2  if(request.getRequestURI().indexOf("login.jsp")!=-1 
3   ||request.getRequestURI().indexOf("servlet/LoginServlet")!=-1 
4   ||request.getRequestURI().indexOf("fail.jsp")!=-1 
5 ){
6                    arg2.doFilter(arg0, arg1);
7                 return;
8                 }

但這樣也有問題,當不需攔截的url多了,if語句也屢屢需要修改,很麻煩,則可以用 FilterConfig物件。先在xml新增配置,有新的不需要攔截的url,秩序在配置裡新增即可。
複製程式碼

 1     <filter>
 2         <filter-name>LoginFilter</filter-name>
 3         <filter-class>com.imooc.filter.LoginFilter</filter-class>
 4         <init-param>
 5             <param-name>noLoginPaths</param-name>
 6             <param-value>login.jsp;fail.jsp;LoginServlet</param-value> //在此新增不需攔截的url
 7         </init-param>
 8         <init-param>
 9             <param-name>charset</param-name> //防止中文亂碼
10             <param-value>UTF-8</param-value>
11         </init-param>
12     </filter>
13     <filter-mapping>
14         <filter-name>LoginFilter</filter-name>
15         <url-pattern>/*</url-pattern>
16     </filter-mapping>

在dofilter中得到此物件 LoginFilter.java

 1 public class LoginFilter implements Filter {
 2     private FilterConfig config;  //這裡定義一下
 3     @Override
 4     public void destroy() {
 5 
 6     }
 7     @Override
 8     public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
 9 
10         HttpServletRequest request = (HttpServletRequest) arg0;
11         HttpServletResponse response = (HttpServletResponse) arg1;
12         HttpSession session = request.getSession();
13         String noLoginPaths = config.getInitParameter("noLoginPaths"); //已獲取filterconfig物件,可以獲取其中屬性
14         
15         String charset = config.getInitParameter("charset");
16         if(charset==null){
17             charset = "UTF-8";
18         }
19         request.setCharacterEncoding(charset);
20         
21         if(noLoginPaths!=null){
22             String[] strArray = noLoginPaths.split(";");  //對屬性的值分割。分別放行
23             for (int i = 0; i < strArray.length; i++) {
24                 if(strArray[i]==null || "".equals(strArray[i]))continue;
25         if(request.getRequestURI().indexOf(strArray[i])!=-1 ){
26                     arg2.doFilter(arg0, arg1);
27                     return;
28                 }
29             }
30         }
31         if(session.getAttribute("username")!=null){
32             arg2.doFilter(arg0, arg1);
33         }else{
34             response.sendRedirect("login.jsp");
35         }
36     }
37     @Override
38     public void init(FilterConfig arg0) throws ServletException {
39         config = arg0;  //在初始化時把次物件賦值
40     }
41 
42 }
//執行順序:最先初始化init(),然後dofilter函式    最後destory()

這裡,這個登入案例就完成了。

那【request -> filter1 -> filter2 ->filter3 -> …. -> request resource。】是什麼呢

就是一個url-partten對應了多個filter,一個url,被攔截了好幾次。
複製程式碼

 1   <filter>
 2         <filter-name>FirstFilter</filter-name>
 3         <filter-class>com.imooc.filter.FirstFilter</filter-class>
 4  </filter>
 5     <filter>
 6         <filter-name>SecondFilter</filter-name>
 7         <filter-class>com.imooc.filter.SecondFilter</filter-class>
 8     </filter>
 9 
10     <filter-mapping>
11         <filter-name>FirstFilter</filter-name>
12         <url-pattern>/index.jsp</url-pattern> 
13     </filter-mapping>
14    <filter-mapping>
15         <filter-name>SecondFilter</filter-name>
16         <url-pattern>/index.jsp</url-pattern>
17     </filter-mapping>

這樣就存在一個過濾器鏈,按xml中順序執行。

index.jsp

1   <body>
2     This is my JSP page. <br>
3     <%
4     System.out.println("到了index.jsp");
5      %>
6   </body>

FirstFilter.java

 1 public class FirstFilter implements Filter {
 2 
 3     @Override
 4     public void destroy() {
 5         System.out.println("destroy---FirstFilter");
 6     }
 7 
 8     @Override
 9     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
10         System.out.println("start----doFilter--FirstFilter");
11         chain.doFilter(request, response);
12         HttpServletRequest req =(HttpServletRequest) request;
13         HttpServletResponse response2 =(HttpServletResponse) response;

19         System.out.println("end------doFilter--FirstFilter");
20     }
21 
22     @Override
23     public void init(FilterConfig filterConfig) throws ServletException {
24         System.out.println("init----FirstFilter");
25     }
26 
27 
28 }

SecondFilter.java

1 public class SecondFilter implements Filter {
 2 
 3     @Override
 4     public void destroy() {
 5         System.out.println("destroy-----SecondFilter");
 6     }
 7 
 8     @Override
 9     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
10         System.out.println("start---doFilter--SecondFilter");
11         chain.doFilter(request, response);
12         System.out.println("end---doFilter--SecondFilter");
13     }
14 
15     @Override
16     public void init(FilterConfig filterConfig) throws ServletException {
17 
18         System.out.println("init-----SecondFilter");
19     }
20 
21 }

過濾器鏈具體的執行順序:

在執行專案時,兩個filter類都執行了init()初始化,控制檯輸出:

init—–FirstFilter

init—–SecondFilter

當訪問index.jsp時,進入FirstFilter.java的dofilter函式,控制檯會依次輸出:

start—doFilter–FirstFilter

start—doFilter–SecondFilter

到了index.jsp

end—doFilter–FirstFilter

end—doFilter–SecondFilter

在dofilter函式中,先執行chain.doFilter(request, response);前的程式碼,然後下一個filter鏈的下一個filter,然後進入index.jsp。再繼續依次執行chain.doFilter(request, response);後面的程式碼

Code1表示ilter(request, response);之前的程式碼Code2表示ilter(request, response);之後的程式碼。