笔记六中实现了三种过滤器:字符编码过滤、登录权限过滤、敏感词过滤,但是有个缺陷就是,限定了过滤顺序,而不能实现先进行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>"); } }
自定义过滤器链的编写这个是源码的下载地址。
希望大家多多指教~~
Servlet学习笔记(八)—— 自定义过滤器的编写改进:自定义实现FilterChain,布布扣,bubuko.com
时间: 2024-10-13 11:22:45