Java EE 基礎知識學習(六)

DasYang發表於2017-04-04

這一部分我們要介紹Java EE中的Filter。

Filter可以對使用者的請求進行預處理,同時也可以對HttpServletResponse進行後處理,是一個典型的處理鏈,所以Filter也叫做攔截器。Filter也可以像Servlet一樣對使用者的請求做出響應,但一般我們都會使用Servlet來響應使用者,而不是用Filer。

使用Filter的好處:

  • Filter可以在HttpServletRequest到達Servlet之前,攔截HttpServletRequest
  • Filter可以檢查HttpServletRequest,並且修改HttpServletRequest
  • 可以在HttpServletResponse到達客戶端之前,攔截HttpServletResponse
  • Filter可以檢查HttpServletResponse,並且修改HttpServletResponse
    總結起來,Filter可以幫助我們在使用者的請求訪問Servlet之前,攔截使用者的請求並做出修改,同時也可以幫助我們在伺服器的響應到達使用者客戶端之前,攔截響應並且做出響應的修改。

Filter的種類:

  • 使用者授權的Filter:負責檢查使用者請求並且過濾非法請求
  • 日誌Filter:用來記錄使用者的請求和伺服器的響應
  • 能改變XML內容的XSLT Filter等
  • 負責解碼的Filter:改變響應和請求的編碼
  • Filter負責攔截多個請求或者響應

建立Filter的步驟:

  • 建立一個Filter處理類
  • 配置Filter

建立一個Filter處理類就是寫好一個類,並且繼承Filter,然後在其中的doFilter方法中編寫你的Filter所要做的事情。
配置Filter有兩種方式,一種方式是在web.xml檔案中配置,一種是使用源註解來配置。

下面是一個改變編碼的Filter類,它接收到使用者的請求或者接收到伺服器的響應會對請求或者響應改變他們的編碼:

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

/**
 * Servlet Filter implementation class EncodingFilter
 */
@WebFilter(filterName="encodingFilter",urlPatterns={"/*"})
public class EncodingFilter implements Filter {

    /**
     * Default constructor. 
     */
    public EncodingFilter() {
        // TODO Auto-generated constructor stub
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
        // TODO Auto-generated method stub
    }

    private String str="UTF-8";
    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        // place your code here
        request.setCharacterEncoding(str);
        response.setCharacterEncoding(str);
        // pass the request along the filter chain
        chain.doFilter(request, response);

    }

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
        // TODO Auto-generated method stub
    }

}

在上面的Filter中我們使用了源註解來配置Filter,我們只需要在類程式碼段的上面加入下面程式碼即可:

@WebFilter(filterName="encodingFilter",urlPatterns={"/*"})

上面的程式碼中urlPatterns表示我們要攔截的使用者請求或者響應的url,“/*”表示攔截一切請求或者響應。

或者我們可以在web.xml中加入下面程式碼來配置Servlet:

<filter>
    <!--Filter的名字,相當於@WebFilter中的filterName屬性-->
    <filter-name>encodingFilter</filter-name>
    <!--Filter實現類-->
    <filter-class>EncodingFilter</filter-class>
</filter>
<filter-mapping>
    <!--Filter名字-->
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Filter的幾個示例:

日誌Filter:在這裡我們編寫一個記錄使用者請求的Filter,程式碼如下:

package com.example;

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;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

/**
 * Servlet Filter implementation class Test
 */
@WebFilter("/*")
public class Test implements Filter {

    /**
     * Default constructor. 
     */
    public Test() {
        // TODO Auto-generated constructor stub
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
        // TODO Auto-generated method stub
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        // place your code here
        System.out.println(request.getRemoteAddr());//輸出使用者ip地址
        HttpServletRequest hreq=(HttpServletRequest)request;
        System.out.println(hreq.getRequestURI());//輸出使用者的請求地址
        // pass the request along the filter chain
        chain.doFilter(request, response);
    }

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
        // TODO Auto-generated method stub
    }

}

攔截未登入使用者:大部分web頁面我們都需要使用者登入才可以訪問,而沒有登入的我們將讓頁面跳轉到登入頁面,讓使用者登入,下面的Filter實現的就是這樣的功能,程式碼如下:

package com.example;

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;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * Servlet Filter implementation class Test
 */
@WebFilter("/*")
public class Test implements Filter {

    /**
     * Default constructor. 
     */
    public Test() {
        // TODO Auto-generated constructor stub
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
        // TODO Auto-generated method stub
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        // place your code here
        HttpServletRequest hreq=(HttpServletRequest)request;
        HttpSession session=hreq.getSession();
        String path=hreq.getServletPath();
        String loginPage="/login.jsp";
        String proLogin="/proLogin.jsp";
                    if(session.getAttribute("user")==null&&!path.endsWith(loginPage)&&!path.endsWith(proLogin))
        {
            request.getRequestDispatcher(loginPage).forward(request, response);
        }
        else{
            // pass the request along the filter chain
            chain.doFilter(request, response);
        }
    }

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
        // TODO Auto-generated method stub
    }

}

在上面的程式碼中我們的判斷語句有三個條件:

  1. 使用者沒有登入
  2. 使用者當前不在登入頁面
  3. 使用者當前不在處理登入的頁面
    剛開始編寫這個Filter的時候,很多人可能認為我們只需要判斷使用者有沒有登入就好,如果沒有登入就跳轉到登入頁面就可以了,但是如果你真的這樣做了你的程式可能會報錯,比如使用者沒有登入然後跳轉到了登入頁面,然後使用者輸入使用者名稱和密碼並且點選了登入,這時候程式會有兩個動作,一個是你的登入頁面寫的當使用者登入成功後要跳轉到一定的頁面,另一個動作是請求被Filter攔截了,這時候Filter也有一個當使用者已經登入的時候做的跳轉,導致的結果就是你的程式同一時間出現了兩個跳轉,程式就會報錯,所以我們必須要有下面的兩個條件,這樣才不會導致上述錯誤的發生。

相關文章