三个实例带你走进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();
		}

}
	
}



过滤器的顺序

如果多个过滤器应用于一个资源,必须用部署描述符管理应该先调用哪个一个过滤器



          filter1
         class name
 
  

          filter2

         class name




你可能感兴趣的:(JSP和Servlet学习指南)