首先:init()当容器实例化一个过滤器时,在init()方法中完成调用过滤器之前的所有初始化任务。
然后:真正的工作在doFilter()中完成容器对当前请求应用过滤器时,就会调用doFilter()方法完成过滤功能。该方法有三个参数: doFilter(ServletRequest,ServletResponse,FilterChain)
最后:destroy()容器删除一个过滤器实例时,调用该方法回收清理工作
接下来,开始实践操作
①建立项目,创建filter和servlet
首先,建立一个工程,分别创建下列文件,如下图:
第一个包com.myFilter里面分别创建3个filter.java文件,并在doFile中输出各自语句加以区分即可
Filter1的代码如下(另外2个相同道理创建):
package com.myFilter;
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;
public class Filter1 implements Filter {
public void destroy() {
}
public void init(FilterConfig config) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
System.out.println("filter1 go");//测试请求过滤
chain.doFilter(request, response);
System.out.println("filter1 return");//测试响应过滤
} catch (Exception e) {
e.printStackTrace();
}
}
}
第二个包com.myServlet这个包里面只有一个servlet文件:ServletTest.java
代码:
package com.myServlet;
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;
public class ServletTest extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.println("<h1>hello</h1>");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
需要用到的servlet文件和filter文件已经建好了,接下来就是在web.xml文件下配置
②配置web.xml文件
首先,打开本工程中/WebRoot/WEB-INF下的web.xml文件
一般先配置filter的相关属性,再配置servlet
代码如下(相关注释以标明):
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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_3_0.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter><!-- 声明过滤器实现类和 初始化参数 -->
<filter-name>Filter1</filter-name><!-- 过滤器名 -->
<filter-class>com.myFilter.Filter1</filter-class><!--过滤器类,包括包名 -->
<!—下面这个init-param是设置初始化参数,本次测试没有用到,可以不写 -->
<init-param>
<param-name>a</param-name><!-- 初始化参数名 -->
<param-value>5</param-value><!-- 初始化参数值 -->
</init-param>
</filter>
<filter>
<filter-name>Filter2</filter-name>
<filter-class>com.myFilter.Filter2</filter-class>
</filter>
<filter>
<filter-name>Filter3</filter-name>
<filter-class>com.myFilter.Filter3</filter-class>
</filter>
<filter-mapping><!-- 将过滤器映射到servlet或者URL中,即把过滤器和web资源关联起来 -->
<filter-name>Filter1</filter-name><!-- 上面声明过的过滤器名 -->
<servlet-name> /*</servlet-name><!-- 指定过滤器映射的URL,/*是指全部URL -->
</filter-mapping>
<filter-mapping>
<filter-name> Filter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Filter3</filter-name>
<servlet-name>ServletTest</servlet-name><!-- 指定过滤器映射的servlet -->
</filter-mapping>
<servlet>
<servlet-name>ServletTest</servlet-name>
<servlet-class>com.myServlet.ServletTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletTest</servlet-name>
<url-pattern>/servlet/ServletTest</url-pattern>
</servlet-mapping>
</web-app>
③部署与测试
配置完成后,我们就可以把这个web 项目部署到服务器了(weblogic或者tomcat都行)
如果到此都没出现错误的话,那恭喜你,项目基本上可以运行了
在浏览器输入网址(我这里是用tomcat,所以端口是8080,如果是weblogic的话改成7001即可):http://localhost:8080/FilterTest/servlet/ServletTest
然后页面会显示下图:
如果上面这步没出现错误并显示成功的话,我们返回myeclipse,在控制台我们会看见
ok,做到这里,我们的工作基本完成了。下面要做的就是解决我们的“为什么”!
那么为什么会出现这个结果呢?
我们来看下请求过滤与响应过滤的顺序:
由上图,我们可以很容易知道,当客户在浏览器访问一个页面的时候,客户的请求会先经过servlet过滤器的处理,最后才到达servlet。
看完这里,我们的问题可以再细化一下,变成两个:
①为什么会3个filter的信息都输出来呢?
②这个输出的顺序能否改变?
第一个问题:
为什么会3个filter的信息都输出来呢?
这里我们可以打开配置好的web.xml文件看看
仔细看下红框位置,我们可以看到,在filter1和filter2的关联URL路径是“/*”,“/*”表示本工程里面的所有URL,就是说,访问任何一个本工程的网页都必须经过filter1和filter2的处理(即每次访问都要调用filter1和filter2的doFilter()方法)。
而filter3关联的却是一个servlet,因为我们上面访问的页面正好是filter3关联的servlet,所以,filter3的信息也会被输出。
PS:因为filter3关联的是一个指定servlet,所以说,我们只要不访问这个servlet(比如:http://localhost:8080/FilterTest/),就可以看到控制台的结果会少了filter3的输出信息。
第二个问题:
输出的顺序能否改变?
先看下比较官方的解释:根据servlet2.3规范filter执行是按照web.xml配置的filter-mapping先后顺序进行执行
也就是说因为我们上面配置的web.xml文件中,过滤器的关联顺序是filter1、filter2、filter3,所以输出的结果是1、2、3、3、2、1
那么,要想改变顺序的话,我们直接把<filter-mapping>的顺序调一下就可以解决问题了。
但是,事情往往不会那么顺利的,当我们把filter3的<filter-mapping>调到第一的时候,控制台输出的结果却不是第一个输出filter3的信息,而且无聊你怎么改,都是没作用。最后查了一下资料,是因为过滤器在关联servlet或URL的时候,是遵循这样的规则的:先找到与URL模式匹配的所有过滤器,最后再找与servlet-name匹配的过滤器。
就是说,因为filter1、filter2关联的是URL,而filter3关联的是servlet,所以无论<filter-mapping>的位置怎么改都好,容器都会先找到URL关联的filter,最后再去找servlet关联的filter!
好了,今天的servlet过滤器初步学习就到此先!