Java 過濾器

過濾器是一個駐留在服務器端的Web組建,能夠截取客戶端和資源之間的請求和響應信息。Web過濾器是不能直接處理客戶端請求,返回客戶端數據的!css

舉例來講:當咱們登陸CSDN或郵箱的時候,輸入應用名和密碼就能夠進入咱們請求的頁面,當咱們點擊退出後,下一次進入時須要從新輸入登陸用戶名與密碼。這是過濾器應用的一個場景。html

咱們須要瞭解:java

  • 過濾器的工做原理
  • 生命週期
  • 過濾器的幾種類型
  • 實例

一、過濾器的工做原理web

 

 

上面的圖簡單說明了過濾器在客戶端和服務器之間的做用。緩存

二、過濾器的生命週期服務器

Web容器啓動的時候,會加載web.xml並執行一次init()函數,而後每次客戶端的請求都會執行doFilter()函數,最後當容器關閉的時候會執行destroy()函數cookie

上面顯示的是一個Web應用程序的結構,全部的Webroot中的內容都是Web的內容,Web-INF下全部的資源都不能直接被url訪問,其餘的文件,用戶能夠經過url訪問。session

 

關於url-pattern的書寫規範,app

(A)一個filter映射一個url:這種狀況下的url與url-pattern中配置的url進行精確匹配。url-pattern中的訪問路徑必須以  /  開頭,表示的是Web應用程序的根目錄,而不是Web站點的根目錄,路徑名稱能夠是多級目錄的形式,例如jsp

<url-pattern>/demo/index.html</url-pattern>

(B)一個filter映射多個url:這種狀況下可使用通配符,須要注意的也有兩種狀況:

(1)*.擴展名,*點前面不能有 「/」

(2)以/開頭,並以 /* 結尾,例如

<url-pattern>/action/*</url-pattern>表示的是整個action目錄下的url

<url-pattern>/</url-pattern>表示的是整個web應用程序下的url

 

過濾器鏈

  1. 在一個web應用中,能夠開發編寫多個Filter,這些Filter組合起來稱之爲一個Filter鏈
  2. Web服務器根據Filter在web.xml文件中的註冊順序(按filter-mapping元素的順序),決定先調用哪一個Filter,當第一個Filter的doFilter方法被調用時,Web服務器會建立一個表明Filter鏈的FilterChain對象傳遞給該方法。
  3. 在doFilter方法中,若是調用了FilterChain對象的doFilter方法,則web服務器會檢查FilterChain對象中是否還有filter,若是有,則調用第2個filter,若是沒有,則調用目標資源。

 

每次客戶端的請求,服務器都會Filter中的doFilter方法,所以,咱們能夠在diFilter中完成一些處理,下面是一個簡單的代碼實現:

public class FilterFirst implements Filter {     
	// 應用被加載時完成過濾器的實例化     
	public FilterFirst() {         
		System.out.println("調用了默認構造方法");     
	}       
	// 初始化:服務器傳入FilterConfig參數     
	public void init(FilterConfig filterConfig) throws ServletException {         
		System.out.println("調用初始化方法");     }       
		// 用戶每次訪問被過濾資源都會調用過濾器的doFilter方法     
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {         
		System.out.println("FilterDemo1第一次攔截");         
		// 對request、response進行預處理,代碼放在chain.doFilter()前         
	chain.doFilter(request, response);// 放行         
		// 對響應信息進行攔截,代碼放在chain.doFilter()後         
		System.out.println("FilterDemo1第二次攔截");     
	}       
	// 應用從服務器上卸載時調用銷燬方法     
	public void destroy() {         
		System.out.println("調用銷燬方法");     
	} 
} 

web.xml的配置

<filter>     
<filter-name>FilterDemo1</filter-name>     
<filter-class>org.flyne.filter.FilterDemo1</filter-class> 
</filter>   

<filter-mapping>     
<filter-name>FilterDemo1</filter-name>     
<url-pattern>/*</url-pattern> 
</filter-mapping> 

  注意代碼中出現的doFilter函數以及其中的參數。ServletRequest request, ServletResponse response, FilterChain chain 所以:

(1)咱們能夠實現將客戶端到服務器,服務器到客戶端的交換數據進行處理。

(2) 處理完成後,咱們必定要記得寫上chain.doFilter(request, response);不然,Web訪問會一直處於被攔截的狀態;

 4、實例

1)SetCharacterEncodingFilter:解決POST請求參數和響應輸出的中文亂碼

public class SetCharacterEncodingFilter implements Filter {       
	private String encoding; //編碼能夠經過<init-param>元素配置       
	public void init(FilterConfig filterConfig) throws ServletException {         
		encoding = filterConfig.getInitParameter("encoding");         
		if(encoding == null){//若是用戶忘記配置,默認encoding爲UTF-8             
			encoding = "UTF-8";         
		}     
	}       

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
	         //只能解決POST請求參數亂碼問題         
	         request.setCharacterEncoding(encoding);         
	         //指定輸出編碼(最後帶上,後面會有說明)         
	         response.setCharacterEncoding(encoding);         
	         //指定輸出流編碼及客戶端應使用的碼錶         
	         response.setContentType("text/html;charset="+encoding);         
	         chain.doFilter(request, response);     
	}       

	public void destroy() {       } 
} 

------------------------web.xml配置------------------------ 
<filter>     
<filter-name>SetCharacterEncodingFilter</filter-name>     
<filter-class>org.flyne.examples.SetCharacterEncodingFilter</filter-class>     
<init-param>         
<param-name>encoding</param-name>         
<param-value>UTF-8</param-value>     
</init-param> 
</filter> 

<filter-mapping>     
<filter-name>SetCharacterEncodingFilter</filter-name>     
<url-pattern>/*</url-pattern> 
</filter-mapping> 

2)2)NoCacheFilter:禁止客戶端緩存動態資源

public void doFilter(ServletRequest req, ServletResponse resp,  FilterChain chain) throws IOException, ServletException {   

	//響應頭爲HTTP協議裏的,需轉換一下     
	HttpServletRequest request = null;     
	HttpServletResponse response = null;     
	try{        
		request = (HttpServletRequest)req;         
		response = (HttpServletResponse)resp;     
	}catch(Exception e){         
		throw new RuntimeException("not-http request or response");     
	}       
		response.setHeader("Expires", "0");     
		response.setHeader("Cache-Control", "no-cache"); //    
		response.setHeader("Pragma", "no-cache");   //這三個參數的意義差很少  
		chain.doFilter(request, response); 
	} 
	------------------------web.xml配置------------------------ 
	<filter>     
	<filter-name>NoCacheFilter</filter-name>     
	<filter-class>org.flyne.examples.NoCacheFilter</filter-class> 
	</filter> 

	<filter-mapping>     
	<filter-name>NoCacheFilter</filter-name>     
	<url-pattern>/servlet/*</url-pattern>     
	<url-pattern>*.jsp</url-pattern> 
	</filter-mapping> 

3)SetCacheExpiresFilter:控制靜態資源緩存時間 (這個主要是理解HTTP協議中Expire的做用)

public class SetCacheExpiresFilter implements Filter {       
	private int htmlExp;//HTML的緩存時間,單位爲小時,下同     
	private int cssExp;//CSS的緩存時間     
	private int jsExp;//JS的緩存時間      
	public void init(FilterConfig filterConfig) throws ServletException {         
		htmlExp = Integer.parseInt(filterConfig.getInitParameter("html"));         
		cssExp = Integer.parseInt(filterConfig.getInitParameter("css"));         
		jsExp = Integer.parseInt(filterConfig.getInitParameter("js"));     
	}       

	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {    
	   	// 響應頭爲HTTP協議裏的,需轉換一下         
	   	HttpServletRequest request = null;         
	   	HttpServletResponse response = null;         
	   	try { 
	   		request = (HttpServletRequest) req;             
	   		response = (HttpServletResponse) resp;         
	   	} catch (Exception e) {             
	   		throw new RuntimeException("not-http request or response");         
	   	}           
	   	//根據請求資源的後綴名肯定緩存時間         
	   	String uri = request.getRequestURI();         
	   	String extName = uri.substring(uri.lastIndexOf(".")+1);         
	   	long expTime = 0;         
	   	if("html".equals(extName)){             	
	   		expTime = System.currentTimeMillis()+htmlExp*60*60*1000;          
	   	}else if("css".equals(extName)){             
	   		expTime = System.currentTimeMillis()+cssExp*60*60*1000;         
	   	}else if("js".equals(extName)){             
	   		expTime = System.currentTimeMillis()+jsExp*60*60*1000;         
	   	}         

	   	response.setDateHeader("Expires", expTime);           
	   	chain.doFilter(request, response);    
	   }       

	   public void destroy() {     } 

	} 

	------------------------web.xml配置------------------------ 

	<filter>     
	<filter-name>SetCacheExpiresFilter</filter-name>     
	<filter-class>org.flyne.examples.SetCacheExpiresFilter</filter-class>     
	<init-param>         
	<param-name>html</param-name>         
	<param-value>1</param-value>     
	</init-param>     
	<init-param>         
	<param-name>css</param-name>         
	<param-value>2</param-value>     
	</init-param>     
	<init-param>         
	<param-name>js</param-name>         
	<param-value>3</param-value>     
	</init-param> </filter> <filter-mapping>     
	<filter-name>SetCacheExpiresFilter</filter-name>     
	<url-pattern>*.html</url-pattern>     
	<url-pattern>*.css</url-pattern>     
	<url-pattern>*.js</url-pattern> 
	</filter-mapping> 

4)AutoLoginFilter :用戶自動登陸

當用戶登錄時,將表單提交到LoginServlet處理,若是用戶勾選了記住我,則將用戶的登錄信息存入Cookie:Cookie名爲「logInfo」,值爲(用戶名的base64加密結果_密碼的md5加密結果)。下面的自動登陸過濾器基於以上信息:

public class AutoLoginFilter implements Filter {       
//表現層同service層打交道     
		private UserService service = new UserServiceImpl();       
		public void init(FilterConfig filterConfig) throws ServletException {     }     
		public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {         
		// 轉爲Http協議的request和response         
			HttpServletRequest request = null;        
		 	HttpServletResponse response = null;         
		 	try {             
		 		request = (HttpServletRequest) req;             
		 		response = (HttpServletResponse) resp;         
		 	} catch (Exception e) {             	
		 		throw new RuntimeException("not-http request or response");         
		 	}           
		 	HttpSession session = request.getSession();         
		 	// 判斷用戶有沒有登陸:只管沒有登陸的        
		 	User sUser = (User) session.getAttribute("user");         
		 	if (sUser == null) {           
		 		Cookie[] cookies = request.getCookies();             
		 		for (int i = 0; cookies != null && i < cookies.length; i++) {                 
		 		Cookie cookie = cookies[i];                 
		 		//名爲logInfo的Cookie記錄了登陸信息(用戶名、密碼)                 
		 		if ("logInfo".equals(cookie.getName())) {                     
		 		String value = cookie.getValue();                     
		 		//Cookie中的用戶名是通過Base64加密的,因此須要解密                     
		 		String username = SecurityUtil.base64Decode(value.split("_")[0]);                     
		 		String password = value.split("_")[1];                     
		 		//Cookie中的密碼是md5加密後的,因此第三個參數爲true                     
		 		User user = service.login(username, password, true);                     
		 		//經過則在session中設置登錄標記                     
		 		if(user!=null){                         
		 			session.setAttribute("user", user);                     
		 		}                     
		 		break;                 
		 		}             
		 	}        
		}         
		chain.doFilter(request, response);     
	}       
public void destroy() {     } 

} 

未完......

參考:MOOC  過濾器 實例來自 http://www.flyne.org/article/636/2

相關文章
相關標籤/搜索