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


一、過濾器 
1.什么是過濾器?

過濾器是一個程序,它先於與之相關的servlet或JSP頁面運行在服務器上。過濾器可附加到一個或多個servlet或JSP頁面上,並且可以檢查進入這些資源的請求信息。在這之后,過濾器可以作如下的選擇: 
①以常規的方式調用資源(即,調用servlet或JSP頁面)。 
②利用修改過的請求信息調用資源。 
③調用資源,但在發送響應到客戶機前對其進行修改。 
④阻止該資源調用,代之以轉到其他的資源,返回一個特定的狀態代碼或生成替換輸出。

2.Servlet過濾器的基本原理:

在Servlet作為過濾器使用時,它可以對客戶的請求進行處理。處理完成后,它會交給下一個過濾器處理,這樣,客戶的請求在過濾鏈里逐個處理,直到請求發送到目標為止。例如,某網站里有提交“修改的注冊信息”的網頁,當用戶填寫完修改信息並提交后,服務器在進行處理時需要做兩項工作:判斷客戶端的會話是否有效;對提交的數據進行統一編碼。這兩項工作可以在由兩個過濾器組成的過濾鏈里進行處理。當過濾器處理成功后,把提交的數據發送到最終目標;如果過濾器處理不成功,將把視圖派發到指定的錯誤頁面。

3.過濾器:只想要在一堆東西里面選個B: 
這里寫圖片描述

4.示例代碼

在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>

如何編寫自定義的過濾器
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); } }
示例2 // 填充100個帶有隨機字母標簽的球 List<String> array = new ArrayList<>(); Random r = new Random(); String[] balls = new String[]{"A", "B", "C"}; for (int i = 0; i < 100; i++) array.add(balls[r.nextInt(3)]); // 只拿出B的來。不明白的自行學習Java 8 array = array.stream().filter(ball -> ball.equals("B")).collect(Collectors.toList())

二、攔截器 
1.什么是攔截器?

攔截器,在AOP(Aspect-Oriented Programming)中用於在某個方法或字段被訪問之前,進行攔截然后在之前或之后加入某些操作。攔截是AOP的一種實現策略。 
在Webwork的中文文檔的解釋為——攔截器是動態攔截Action調用的對象。它提供了一種機制可以使開發者可以定義在一個action執行的前后執行的代碼,也可以在一個action執行前阻止其執行。同時也是提供了一種可以提取action中可重用的部分的方式。 
談到攔截器,還有一個詞大家應該知道——攔截器鏈(Interceptor Chain,在Struts 2中稱為攔截器棧 Interceptor Stack)。攔截器鏈就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或字段時,攔截器鏈中的攔截器就會按其之前定義的順序被調用。

2.攔截器的實現原理:

大部分時候,攔截器方法都是通過代理的方式來調用的。Struts 2的攔截器實現相對簡單。當請求到達Struts 2的ServletDispatcher時,Struts 2會查找配置文件,並根據其配置實例化相對的攔截器對象,然后串成一個列表(list),最后一個一個地調用列表中的攔截器。

3.攔截器:把水流變小點,把魚都攔住!順便發個電: 
這里寫圖片描述

4.示例代碼

在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>
怎么編寫自定義攔截器 
public class FilterIPActionInterceptor extends AbstractInterceptor { /** 日志控制. */ private final Log log = LogFactory.getLog(getClass()); /** * @see com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(com.opensymphony.xwork2.ActionInvocation) */ @Override @SuppressWarnings("unchecked") 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; } } 

 

示例2 作者:知乎用戶 鏈接:https://www.zhihu.com/question/35225845/answer/61876681 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 class River { // 流量 int volume; // 總魚數 int numFish; } class PowerGenerator { double generate (int volume) { // 假設每一百立方米水發一度電 return volume / 100; } } interface Interceptor { void intercept (River river); } class SomeInterceptor implements Interceptor { PowerGenerator generator = new PowerGenerator(); @Override public void intercept (River river) { // 消耗了1000立方米水來發電 int waterUsed = 1000; // 水量減少了1000。請不要跟我討論水電站原理的問題, // 我就那么一比方 river.volume -= waterUsed; // 發電 generator.generate (waterUsed); // 攔截所有的魚 river.numFish = 0; } } class RiverController { Interceptor interceptor; void flow(River river) { // 源頭積累下來的水量和魚 river.volume += 100000 river.numFish += 1000 // 經過了大壩 interceptor.intercept(river); // 下了點雨 river.volume += 1000 } void setInterceptor (Interceptor interceptor) { this.interceptor = interceptor } } class Main { public static void main (String args[]) { RiverController rc = new RiverController; Interceptor inter = new SomeInterceptor(); // 這一步通常叫做控制反轉或依賴注入,其實也沒啥子 rc.setInterceptor(inter); rc.flow(new River()); } }


攔截器與過濾器的區別 :

 1. 攔截器是基於java的反射機制的,而過濾器是基於函數回調。
 2. 攔截器不依賴與servlet容器,過濾器依賴與servlet容器。 
 3. 攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
 4. 攔截器可以訪問action上下文、值棧里的對象,而過濾器不能訪問。 
 5. 在action的生命周期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次攔截器的代  
    碼實現。
 6. Filter基於回調函數,我們需要實現的filter接口中doFilter方法就是回調函數,而interceptor則基於 
    java本身的反射機制,這是兩者最本質的區別。
 7. Filter是依賴於servlet容器的,即只能在servlet容器中執行,很顯然沒有servlet容器就無法來回調
    doFilter方法。而interceptor與servlet容器無關。
 8. Filter的過濾范圍比Interceptor大,Filter除了過濾請求外通過通配符可以保護頁面,圖片,文件等等,
    而Interceptor只能過濾請求。
 9. Filter的過濾例外一般是在加載的時候在init方法聲明,而Interceptor可以通過在xml聲明是guest請求還
    是user請求來辨別是否過濾。

三、監聽器 
1.監聽器(Listener):當一個事件發生的時候,你希望獲得這個事件發生的詳細信息,而並不想干預這個事件本身的進程,這就要用到監聽器。 
這里寫圖片描述

2.示例代碼

作者:知乎用戶
鏈接:https://www.zhihu.com/question/35225845/answer/61876681 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 // 監聽器 interface BedListener { // 監聽器在參數中收到了某個事件,而這個事件往往是只讀的 // 監聽器的方法名通常以"on"開頭 void onBedSound (String sound); } class Neighbor { BedListener listener; // 依然是所謂控制反轉 setListener (BedListener listener) { this.listener = listener; } void doInterestingStuff () { // 根據當地法律法規,部分內容無法顯示 // 將事件發送給監聽器 listener.onBedSound("嘿咻"); listener.onBedSound("oyeah"); } } class Main { public static void main (String args[]) { Neighbor n = new Neighbor(); n.setListener (sound -> generatePower()); n.doInterestingStuff(); } private static void generatePower() { // 根據當地法律法規,部分內容無法顯示 } }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM