java web 過濾器跟攔截器的區別和使用

南夏發表於2015-12-07
1、首先要明確什麼是攔截器、什麼是過濾器
   1.1 什麼是攔截器: 
    攔截器,在AOP(Aspect-Oriented Programming)中用於在某個方法或欄位被訪問之前,進行攔截然後在之前或之後加入某些操作。攔截是AOP的一種實現策略。 
   在Webwork的中文文件的解釋為——攔截器是動態攔截Action呼叫的物件。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的程式碼,也可以在一個action執行前阻止其執行。同時也是提供了一種可以提取action中可重用的部分的方式。 
    談到攔截器,還有一個詞大家應該知道——攔截器鏈(Interceptor Chain,在Struts 2中稱為攔截器棧           Interceptor Stack)。攔截器鏈就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或欄位時,攔截器鏈中的攔截器就會按其之前定義的順序被呼叫。 
1.2.    攔截器的實現原理: 
 大部分時候,攔截器方法都是通過代理的方式來呼叫的。Struts 2的攔截器實現相對簡單。當請求到達Struts 2的ServletDispatcher時,Struts 2會查詢配置檔案,並根據其配置例項化相對的攔截器物件,然後串成一個列表(list),最後一個一個地呼叫列表中的攔截器。
1.3 什麼是過濾器
過濾器是一個程式,它先於與之相關的servlet或JSP頁面執行在伺服器上。過濾器可附加到一個或多個servlet或JSP頁面上,並且可以檢查進入這些資源的請求資訊。在這之後,過濾器可以作如下的選擇:
①以常規的方式呼叫資源(即,呼叫servlet或JSP頁面)。
②利用修改過的請求資訊呼叫資源。
③呼叫資源,但在傳送響應到客戶機前對其進行修改。
④阻止該資源呼叫,代之以轉到其他的資源,返回一個特定的狀態程式碼或生成替換輸出。
 
1.4 Servlet過濾器的基本原理
在Servlet作為過濾器使用時,它可以對客戶的請求進行處理。處理完成後,它會交給下一個過濾器處理,這樣,客戶的請求在過濾鏈裡逐個處理,直到請求傳送到目標為止。例如,某網站裡有提交“修改的註冊資訊”的網頁,當使用者填寫完修改資訊並提交後,伺服器在進行處理時需要做兩項工作:判斷客戶端的會話是否有效;對提交的資料進行統一編碼。這兩項工作可以在由兩個過濾器組成的過濾鏈裡進行處理。當過濾器處理成功後,把提交的資料傳送到最終目標;如果過濾器處理不成功,將把檢視派發到指定的錯誤頁面。
 
2、攔截器與過濾器的區別 : 
     1. 攔截器是基於java的反射機制的,而過濾器是基於函式回撥。
     2. 攔截器不依賴與servlet容器,過濾器依賴與servlet容器。 
     3. 攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
     4. 攔截器可以訪問action上下文、值棧裡的物件,而過濾器不能訪問。 
     5. 在action的生命週期中,攔截器可以多次被呼叫,而過濾器只能在容器初始化時被呼叫一次

攔截器的程式碼實現(以struts2為例):
1、在xml檔案中如何定義攔截器
<interceptors>
 <interceptor name="filterIPInterceptor"
                         class="com.xxxx.web.FilterIPActionInterceptor" />
<interceptor-stack name="filterIPStack">
<interceptor-ref name="defaultStack" />
                              
<interceptor-ref name="filterIPInterceptor" />
</interceptor-stack>
</interceptors>
 
2、怎麼遍別寫自定義攔截器 
 
public class FilterIPActionInterceptor extends AbstractInterceptor
{
    /** 日誌控制. */
    private final Log log = LogFactory.getLog(getClass());

    public String intercept(ActionInvocation invocation) throws Exception
    {
        String result = null;
        // 獲得當前方法名.
        String methodName = invocation.getInvocationContext().getName();
        String currIp = null;
        try
        {
            if (invocation.getAction() instanceof PortletAction)
            {
                PortletAction action = (PortletAction) invocation.getAction();
                currIp = action.getRequest().getRemoteAddr();
            }
            String ip = ApplicationResource.getHotValue("ALLOW_CACHE_IP");
 
            if (StringUtils.isBlank(ip) || StringUtils.isBlank(currIp))
            {
                log.error("允許重新整理的IP不存在或當前請求的IP非法.");
                throw new NoAllowIPException();
            }
            else
            {
                String[] ips = ip.split(",");
                boolean errorIp = true;
                for (String s : ips)
                {
                    if (s.equals(currIp))
                        errorIp = false;
                }
                // 判斷IP
                if (errorIp)
                    throw new NoAllowIPException();
            }
            result = invocation.invoke();//呼叫被攔截的方法
        }
        catch (Exception e)
        {
            log.error("異常類名:" + invocation.getAction().getClass());
            log.error("異常方法:" + methodName, e);
            throw e;
        }
 
        return result;
    } 
}




//自定義攔截器(實現攔截器介面implements Interceptor)
public class CheckPrivilegeIntercetor implements Interceptor {
	
	public void destroy() {
	}
	public void init() {
	}	
	public String intercept(ActionInvocation invocation) throws Exception {
//		System.out.println("---------> 之前");
//		String result = invocation.invoke(); // 放行
//		System.out.println("---------> 之後");
//		return result;


		// 從session裡面獲取使用者資訊
		User user = (User) ActionContext.getContext().getSession().get("user"); // 當前登入使用者
		String namespace = invocation.getProxy().getNamespace();
		String actionName = invocation.getProxy().getActionName();
		String privUrl = namespace + actionName; // 對應的許可權URL
		System.out.println("==========================================");
		System.out.println(privUrl);
		// 在網址輸入路徑,如果未登入
		if (user == null) {
			if (privUrl.startsWith("/user_login")) {
				// "/user_loginUI"
				// 如果是去登入,就放行
				return invocation.invoke();
			} else {
				// 如果不是去登入,就轉到登入頁面
				return "loginUI";
			}
		}
		
		
		// 如果已登 錄,就判斷許可權
		else {
			if (user.hasPrivilegeByUrl(privUrl)) {
				// 如果有許可權,就放行
				return invocation.invoke();
			} else {
				// 如果沒有許可權,就轉到提示頁面
				return "noPrivilegeError";
			}
		}
	}
	


}

3、怎麼編寫過濾器
 
     1、在web.xml裡面配置自定義的攔截器
        <filter>
<filter-name>Redirect Filter</filter-name>
<filter-class>com.xx.filter.RedirectFilter</filter-class>
</filter>
 
<filter-mapping>
<filter-name>Redirect Filter</filter-name>
<url-pattern>/xx/xx/*</url-pattern>
 
</filter-mapping>
 
    2、如何編寫自定義的攔截器
public class RedirectFilter implements Filter {
       public void doFilter(ServletRequest request, ServletResponse response,
              FilterChain filterChain) throws IOException, ServletException {
    // 獲取URL
   Long startTime = null;
        if (log.isDebugEnabled())
        {
            startTime = System.currentTimeMillis();
        }
              HttpServletRequest httpRequest = (HttpServletRequest) request;
                          String url = httpRequest.getRequestURL().toString();
                      if (url == null || url.trim().length() == 0) {
                                    return;
                                                   }
                     if (url.indexOf(luceneCreateMapping) != -1
                                  || url.indexOf(luceneSearchMapping) != -1) {
                               doFilterForxxx(request, response, url);
                               } else {
                                     doxxxx(request, response, url);
                                    }
         if (log.isDebugEnabled())
        {
            long endTime = System.currentTimeMillis();
            Thread currentThread = Thread.currentThread();
            String threadName = currentThread.getName();
            log.debug("[" + threadName + "]" + "< "
                    + this.getClass().getName() + " " + url + " "
                    + (endTime - startTime) + " ms");
        }
// 啟用下一個Filter
 filterChain.doFilter(request, response);
 
        }
}

相關文章