1. 程式人生 > >三個例項帶你走進web過濾器Filter API

三個例項帶你走進web過濾器Filter API

web過濾器

  過濾器是指攔截請求,並對傳給被請求資源的ServletRequest或ServletResponse進行處理的一個物件。

過濾器可用於登入、加密和解密、對話檢查、圖片轉換等待。過濾器可以配置攔截一個或者多個資源

1.Filter API

過濾器必須實現javax.servret.Filter介面,這個介面暴露三個生命週期方法:init,doFilter,destroy

當過濾器啟動服務時,Servlet容器就會呼叫init方法。這個方法指呼叫一次

void init(FilterConfig filterConfig)

filterConfig可用於獲取ServletContext物件,或者獲取初始化屬性(getInitParameter)

doFilter方法時過濾器核心

void doFilter(ServletRequest request ,ServletResponse response,FilterChain chain)

可以在ServletRequest 中新增屬性,或者在ServletResponse新增一個標頭

也可以獲取HttpServletRequest物件

doFilter方法實現中的最後一行程式碼應該時呼叫FilterChain中的doFilter(request,response)方法

表示放行,通常會引發下一個過濾器被呼叫。

void destroy()

這個方法在過濾器即將終止服務之前,有servlet容器呼叫

2.過濾器的配置

確定要攔截哪些資源  (urlPatterns  value)

要傳給init方法的啟動初始值(initParams)  可通過getParameterNames   和getParameter方法來獲取

給過濾器七個名字(filterName)

可以通過@webFilter註解 和部署描述符中宣告

下面通過三個例項來帶你瞭解神祕的過濾器

例項一:日誌過濾器

通過一個過濾器,用於在一個文字檔案中記錄請求的URI。從日誌中 可以推斷出一些有價值的資訊,例如

應用程式中哪一項資源最受歡迎,獲知網站每天哪個時間段的訪問量最多

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

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.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
@WebFilter(filterName="LoggingFilter",urlPatterns={"/*"},
initParams={
        @WebInitParam(name="logFileName", value="log.txt"),  //檔名
        @WebInitParam(name="prefix",value="URI:")} )         //每個日誌條目的字首
public class LoggingFilter implements Filter {
 
	private String prefix;
	private PrintWriter logger;
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		System.out.println("destroying filter");
		if(logger!=null){
			logger.close();
		}

	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		// TODO Auto-generated method stub
		System.out.println("LoggingFilter.doFilter");
		HttpServletRequest httpServletRequest=(HttpServletRequest) arg0;
		logger.println(new Date()+" "+prefix+
				httpServletRequest.getRequestURL());      
		logger.flush();
		arg2.doFilter(arg0, arg1);

	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		prefix=arg0.getInitParameter("prefix");
		String logFileName=arg0.getInitParameter("logFileName");
		String appPath=arg0.getServletContext().getRealPath("/");//利用FilterConfig獲取servletContext物件的getRealPath方法來獲取應用程式的絕對路徑
		
		System.out.println("logFileName:"+logFileName);
		try{
			logger=new PrintWriter(new File(appPath,logFileName));
		}catch(FileNotFoundException e){
			e.printStackTrace();
			throw new ServletException(e.getMessage());
		}

		
	}

}

例項2:圖片保護過濾器

本例防止通過在瀏覽器的位址列直接輸入url來下載圖片。只有當在頁面中點選圖片的連結時,圖片才會下載

過濾器通過檢視HTTP標頭referer的值來判斷,只有當標頭不為空時,才放行

標頭為空時表示請求沒有相當的引用頁

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;
@WebFilter(filterName="ImageProtectorFilter",urlPatterns={"*.png","*.jpg","*.gif"})
public class ImageProtectorFilter implements Filter {

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		// TODO Auto-generated method stub
		System.out.println("imageProtextFilter doFilter");
		HttpServletRequest httpServletRequest=(HttpServletRequest) arg0;
		String referrer=httpServletRequest.getHeader("referer");
		System.out.println("referer:"+referrer);
		if(referrer!=null){
			arg2.doFilter(arg0, arg1);
		}else{
			throw new ServletException("Image not available");
		}

	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub

	}

}

例項3:下載計數過濾器

本例的下載計數過濾器可以計算某一個資源被下載了多少次。當你想要知道你的視訊的受歡迎程度或者文件的下載次數

這個就很有幫助,將這些資料儲存在一個屬性檔案中,並且多個執行緒可以同時訪問一個過濾器,因此需要一個執行緒安全性

的問題需要解決,這個例子通過利用Queue和Executor來解決這個執行緒安全性問題,將所有進來的請求都在一個執行緒的

Executor的佇列中放置一個任務。放置任務為非同步操作,比較快。Executor每次從佇列中取出一個專案,消除了多執行緒

訪問該屬性檔案的可能性

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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;
@WebFilter(filterName="DownloadCounterFilter",urlPatterns="/*")
public class DownloadCounterFilter implements Filter {

	ExecutorService executorService=Executors.newSingleThreadExecutor();//ExecutorService是Executor的一個子類
	Properties downloadLog;   //Properties為HashTable的子類,執行緒安全
	File logFile;
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		executorService.shutdown();

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		HttpServletRequest httpServletRequest=(HttpServletRequest) request;
		
		final String uri=httpServletRequest.getRequestURI();
		executorService.execute(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				String property=downloadLog.getProperty(uri);
				if(property==null){
					downloadLog.setProperty(uri, "1");
					
				}else{
					int count=0;
					try{
						count=Integer.parseInt(property);
					}catch(NumberFormatException e){
						
					}
					count++;
					downloadLog.setProperty(uri, Integer.toString(count));
				}
				try{
					downloadLog.store(new FileWriter(logFile), "");
				}catch(IOException e){
					e.printStackTrace();
				}
			}
		});
		chain.doFilter(request, response);

	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		System.out.println("DownloadCounterFilter init");
		String appPath=filterConfig.getServletContext().getRealPath("/");
		logFile=new File(appPath,"downloadLog.txt");
		if(!logFile.exists()){
		try{	
			logFile.createNewFile();
			}
		catch(IOException e){
			e.printStackTrace();
		}
	}
		downloadLog=new Properties();
		try {
			downloadLog.load(new FileReader(logFile));  //將資料存入檔案中
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

}
	
}
過濾器的順序

如果多個過濾器應用於一個資源,必須用部署描述符管理應該先呼叫哪個一個過濾器

<filter>
         <filter-name> filter1</filter-name>
         <filter-class>class name</filter-class>
</filter>

<filter>

         <filter-name> filter2</filter-name>

         <filter-class>class name</filter-class>

</filter>