首页 > 代码库 > Servlet学习笔记(八)—— 自定义过滤器的编写改进:自定义实现FilterChain

Servlet学习笔记(八)—— 自定义过滤器的编写改进:自定义实现FilterChain

      笔记六中实现了三种过滤器:字符编码过滤、登录权限过滤、敏感词过滤,但是有个缺陷就是,限定了过滤顺序,而不能实现先进行request过滤,最后response过滤,并且中间几项过滤的顺序不能动态改变。所以这里做个改进,实现一个过滤顺序的FilterChain。

      多个Filter的执行顺序在这篇博文中得到很仔细的讲解,总结一点,多个过滤器的执行顺序是根据web.xml中不同<filter-mapping>的顺序来先后执行的,比如:

<?xml version="1.0" encoding="UTF-8"?>   
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">   
    <welcome-file-list>   
        <welcome-file>index.jsp</welcome-file>   
    </welcome-file-list>   
    <filter>   
        <filter-name>firstFilter</filter-name>   
        <filter-class>com.test.filter.FirstFilter</filter-class>   
    </filter>   
    <filter>   
        <filter-name>secondFilter</filter-name>   
        <filter-class>com.test.filter.SecondFilter</filter-class>   
    </filter>   
    <filter-mapping>   
        <filter-name>secondFilter</filter-name>   
        <url-pattern>/*</url-pattern>   
    </filter-mapping>   
    <filter-mapping>   
        <filter-name>firstFilter</filter-name>   
        <url-pattern>/*</url-pattern>   
    </filter-mapping>   
  
    <servlet>   
        <servlet-name>firstServlet</servlet-name>   
        <servlet-class>com.alimama.servlet.FirstServlet</servlet-class>   
    </servlet>   
    <servlet-mapping>   
        <servlet-name>firstServlet</servlet-name>   
        <url-pattern>/firstServlet</url-pattern>   
    </servlet-mapping>   
</web-app>   

      将会先执行secondFilter,再执行firstFilter。

      下面是截取的一段实现Filter接口的doFilter代码,用户自定义的Filter都实现了这个接口:

 public void doFilter(ServletRequest request, ServletResponse response,   
            FilterChain chain) throws IOException, ServletException {   
        System.out.println("before invoke secondFilter's chain.doFilter() ..");   
        chain.doFilter(request, response);   
        System.out.println("after invoke secondFilter's chain.doFilter() ..");   
    }   

      可以看到第四行的chain.doFilter(request,response);这句代码是Servlet里的Filter技术的核心,它的主要职能是将请求传递给下一个Filter。不是一下子全部初始化所有的Filter对象。

      依据这个思想,我自己定义了一个FilterChain来实现多个过滤器的过滤顺序。

//FilterChain.java
package lewa;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class FilterChain {
	//private static final String[] filters={"LoginFilter","WordFilter"};
	private static final Filter[] filters={new LoginFilter(),new WordFilter()};
	private static int count=0;
	public void doFilter(ServletRequest request,ServletResponse response,FilterChain fc) throws InstantiationException, IllegalAccessException, Exception{
		if(count<filters.length){	
			//Class<Filter> cls=(Class<Filter>)Class.forName(filters[count]);
			//cls.doFilter(request, response);
			filters[count++].doFilter(request, response, fc);
		}
	}
}

      静态成员变量filters里的过滤器实例的顺序可以自行定义,以后想更改过滤顺序只要改这个String数组就可以。

      相应的其他Filter也做了更改:

//Filter.java
package lewa;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public interface Filter {
	public void init();
	public void doFilter(ServletRequest reuqest,ServletResponse response,FilterChain fc)throws Exception;
	public void destroy();
}

//EncodingFilter.java
package lewa;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class EncodingFilter implements Filter{

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

	@Override
	public void doFilter(ServletRequest reuqest, ServletResponse response,FilterChain fc)throws InstantiationException, IllegalAccessException, Exception{
		// TODO Auto-generated method stub
		reuqest.setCharacterEncoding("UTF-8");
		fc.doFilter(reuqest, response,fc);
		response.setContentType("text/html;charset=UTF-8");
	}

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

//LoginFilter.java
package lewa;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginFilter implements Filter{
	public LoginFilter(){}

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

	@Override
	public void doFilter(ServletRequest reuqest, ServletResponse response,FilterChain fc)
			throws  Exception {
		// TODO Auto-generated method stub
		HttpServletRequest req=(HttpServletRequest)reuqest;
		HttpServletResponse resp=(HttpServletResponse)response;
		HttpSession session=req.getSession();
		if(session.getAttribute("username")==null){
			resp.sendRedirect("login.html");
		}else{
		fc.doFilter(reuqest, response,fc);//这里必须有一个else,不能直接是执行下一个Filter,因为如果未登陆,
那么敏感词过滤就不必再做,而且可以尝试不加else,你会发现,未登陆前留言会跳转到登陆界面,登陆之后再回到留言界面,
这时候count已经不满足count<filters.length,所以此时敏感词过滤将不会执行。 
                }
	}

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

}

//WordFilter.java
package lewa;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class WordFilter implements Filter{

	private static Pattern pattern=null;
	public static String str=null;
	
	private void loadKeyWordProperties(){
		StringBuffer patternBuffer = new StringBuffer();
		try{
			InputStream in =WordFilter.class.getClassLoader().getResourceAsStream("words.properties");
			Properties properties = new Properties();
			properties.load(in);
			Enumeration<?> enu=properties.propertyNames();
			while(enu.hasMoreElements()){
				patternBuffer.append((String)enu.nextElement()+"|");
			}
			patternBuffer.deleteCharAt(patternBuffer.length()-1);
			pattern = Pattern.compile(new String(patternBuffer.toString().getBytes("ISO-8859-1"),"UTF-8"));
		}catch(IOException e){
			e.printStackTrace();
		}
	}
	@Override
	public void init() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest reuqest, ServletResponse response,FilterChain fc)
			throws InstantiationException, IllegalAccessException, Exception {
		// TODO Auto-generated method stub		
		loadKeyWordProperties();
		str=reuqest.getParameter("liuyan");
		try{
			Matcher m=pattern.matcher(str);
			str=m.replaceAll("**");
		}catch(Exception e){
			e.printStackTrace();
		}		
		fc.doFilter(reuqest, response,fc);
	}

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

       最后Servlet里的代码更改:

package lewa;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class Summary
 */
public class Summary extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Summary() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		Filter filter=new EncodingFilter();
		FilterChain  fc=new FilterChain();
		try {
			filter.doFilter(request, response,fc);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		PrintWriter out=response.getWriter();
		HttpSession session=request.getSession();
		String name=(String) session.getAttribute("username");
		if(name!=null&&!"".equals(name)) {
			name=new String(name.getBytes("ISO-8859-1"),"UTF-8");
		}
		out.println("<html><head><title>留言板内容</title></head><body>");
		out.println("用户名:"+name);
		out.println("<br/>"+WordFilter.str+"</body></html>");		
	}
}
 

自定义过滤器链的编写这个是源码的下载地址。

希望大家多多指教~~可怜