javax. servlet. Filter接口(过滤器)
javax.servlet.Filter接口是Servlet的过滤器,它是Servlet 2.3规范中新增加的一个功能.
主要用于完成一些通用的操作,如编码的过滤、判断用户的登录状态等。是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在Servlet 进行响应处理的前后实现一些特殊功能。它是部署在服务器上运行的。
当用户通过浏览器访问服务器中的目标资源时,首先会被 Filter 拦截,在 Filter 中进行预处理操作,然后再将请求转发给目标资源。当服务器接收到这个请求后会对其进行响应,在服务器处理响应的过程中,也需要将响应结果经过滤器处理后,才发送给客户端。
在 javax.servlet.Filter 接口中定义了三个方法
init(FilterConfig filterConfig) | 用于初始化过滤器。我们可以将在程序运行最初阶段的一些操作定义在初始化方法中来实现。 |
doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | 实现对请求和响应对象进行过滤操作。我们可以将对请求和响应信息过滤的操作定义在该方法中来实现。 |
destroy() | 用于释放被 Filter 对象打开的资源。我们可以将关闭数据库和 I/O 流的动作定义在该方法中实现。 |
表中的三个方法都是可以表现 Filter 生命周期的方法,其中
init() 方法在 Web 应用程序加载时会被调用,
destroy() 方法在 Web 应用程序卸载(或关闭)时被调用,
这两个方法都只会被调用一次,
而 doFilter() 方法会被调用多次(只要客户端有请求时就会被调用),
过滤器所有的工作集中在 doFilter() 方法中。
下面通过案例演示 Filter 程序如何对 Servlet 程序的调用过程进行拦截。
1.创建一个Servlet,充当目标资源
package com.wangxing.servlet;
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 TestServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
PrintWriter out=resp.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset=\"UTF-8\">");
out.println("<title></title>");
out.println("</head>");
out.println("<body>");
out.println("<center>");
out.println("<h1>被访问的目标资源</h1>");
out.println("</center>");
out.println("</body>");
out.println("</html>");
out.close();
}
}
2.创建过滤器
- 创建新类,实现javax.servlet.Filter接口
- 重写init、doFilter、destroy方法
- 在doFilter中编写具体过滤动作
- Web.xml配置过滤器
package com.wangxing.filter;
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 TestFilter implements Filter{
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("初始化过滤器的方法--init,服务器启动的时候执行一次");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
System.out.println("过滤请求和响应的方法--doFilter,会被执行多次");
//将请求传递给目标资源
chain.doFilter(req, resp);
}
@Override
public void destroy() {
System.out.println("销毁过滤器对象的方法--destroy,服务器关闭/移除程序的时候执行一次");
}
}
web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<filter>
<filter-name>test</filter-name>
<filter-class>com.wangxing.filter.TestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>test</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>com.wangxing.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
<servlet>
</web-app>
2.过滤器中常见的接口
FilterConfig接口
FilterConfig接口与ServletConfig接口相似。
FilterConfig 是 Servlet API 提供的一个用于获取 Filter 程序在 web.xml 文件中的配置信息的接口,该接口封装了 Filter 程序在 web.xml 中的所有注册信息,并且提供了一系列获取这些配置信息的方法。
常用的方法:
String getFilterName() | 得到配置在web.xml文件中<filter-name>的值 |
String getInitParameter(String name) | 得到配置在web.xml文件中<filter>中<init-param>的初始化值 |
例如:
web.xml
<!-- TestFilter -->
<filter>
<filter-name>test</filter-name>
<filter-class>com.wangxing.filter.TestFilter</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>zhangsan</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>test</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
package com.wangxing.filter;
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 TestFilter implements Filter{
@Override
public void init(FilterConfig config) throws ServletException {
System.out.println("TestFilter初始化过滤器的方法--init");
//String getInitParameter(String name)--得到web.xml文件中filter中配置的初始化参数值
String name=config.getInitParameter("username");
System.out.println("name=="+name);
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
System.out.println("TestFilter--过滤请求和响应");
//将请求传递给目标资源
chain.doFilter(req, resp);
}
@Override
public void destroy() {
System.out.println("TestFilter销毁过滤器对象的方法--destroy次");
}
}
3.Filter的三种映射方式
1.使用通配符*拦截用户的所有请求【*--所有请求】
<filter>
<filter-name>myfilter1</filter-name>
<filter-class>com.wangxing.filter.MyTestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myfilter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.拦截不同方式的访问请求
在 web.xml 文件中,每一个 <filter-mapping> 元素都可以配置一个 Filter 所负责拦截的资源。在 <filter-mapping> 元素中有一个特殊的子元素 <dispatcher>,该元素用于指定过滤器所拦截的资源被 Servlet 容器调用的方式。
<dispatcher>的取值有4种:
REQUEST | 当用户直接访问页面时,Web 容器将会调用过滤器 如果是RequestDispatcher的include()或forward()方法访问,那么该过滤器将不会被调用 |
INCLUDE | 如果目标资源通过 RequestDispatcher 的 include() 方法访问 |
FORWARD | 如果目标资源通过 RequestDispatcher 的 forward() 方法访问 |
ERROR | 目标资源通过声明式异常处理机制调用,那么该过滤器将会被调用 |
3.拦截不同访问路径的访问请求
通过设置<filter-mapping> 元素中的<url-pattern>指定不同的访问路径,来确定哪些资源可以访问当前过滤器,哪些资源不可以访问当前过滤器。
例如:
<!--MyTestFilter-->
<filter>
<filter-name>myfilter1</filter-name>
<filter-class>com.wangxing.filter.MyTestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myfilter1</filter-name>
<url-pattern>/mytest</url-pattern>
</filter-mapping>
<!--MyOtherFilter-->
<filter>
<filter-name>myfilter2</filter-name>
<filter-class>com.wangxing.filter.MyOtherFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myfilter2</filter-name>
<url-pattern>/myother</url-pattern>
</filter-mapping>
<!--MyTestServlet-->
<servlet>
<servlet-name>mytest</servlet-name>
<servlet-class>com.wangxing.servlet.MyTestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mytest</servlet-name>
<url-pattern>/mytest</url-pattern>
</servlet-mapping>
<!--OtherTestServlet-->
<servlet>
<servlet-name>myother</servlet-name>
<servlet-class>com.wangxing.servlet.OtherTestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myother</servlet-name>
<url-pattern>/myother</url-pattern>
</servlet-mapping>
4.FilterChain(过滤器链)
在一个 Web 应用程序中可以注册多个过滤器程序,每个过滤器程序都可以针对某一个 URL 进行拦截。如果多个过滤器程序都对同一个URL进行拦截,那么这些过滤器就会组成一个过滤器链--FilterChain
FilterChain接口中只有一个doFilter(ServletRequest req,ServletResponse resp)方法,该方法的作用是让过滤器链上的当前过滤器放行,使请求进入下一个过滤器,直至目标资源。
在上图中,当浏览器访问 Web 服务器中的资源时,需要经过两个过滤器 Filter1 和 Filter2。首先 Filter1 会对这个请求进行拦截,在 Filter1 中处理完请求后,通过Filter 链 FilterChain 对象调用 doFilter() 方法将请求传递给 Filter2,Filter2 处理用户请求后同样FilterChain 对象调用 doFilter() 方法,最终将请求发送给目标资源。当 Web 服务器对这个请求做出响应时,也会被过滤器拦截,但这个拦截顺序与之前相反,最终将响应结果发送给客户端浏览器。
Filter接口[过滤器] 1个 | 1.init(FilterConfig arg0) 2.doFilter(ServletRequest req,ServletResponse resp, FilterChain chain)过滤请求/响应 3.destroy() |
FilterChain接口[过滤器链] 多个 | doFilter(ServletRequest req,ServletResponse resp) 将请求/响应传递给下一个过滤器/目标资源 过滤器链FilterChain中的doFilter方法需要在过滤器Filter的doFilter中调用,才能将请求/响应传递给下一个过滤器/目标资源。 |
例如:
<filter>
<filter-name>base</filter-name>
<filter-class>com.wangxing.filter.BaseFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>base</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>myfilter1</filter-name>
<filter-class>com.wangxing.filter.MyTestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myfilter1</filter-name>
<url-pattern>/mytest</url-pattern>
</filter-mapping>
<filter>
<filter-name>myfilter2</filter-name>
<filter-class>com.wangxing.filter.MyOtherFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myfilter2</filter-name>
<url-pattern>/mytest</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>mytest</servlet-name>
<servlet-class>com.wangxing.servlet.MyTestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mytest</servlet-name>
<url-pattern>/mytest</url-pattern>
</servlet-mapping>
http://localhost:8080/TestFilterDemo3/mytest
过滤器链中的每一个过滤器在执行的时候,与在web.xml文件中配置的顺序一致。
5.ServletFilter实现全站统一编码,解决中文乱码问题
注意:tomcat8以后默认编码格式是utf-8;7之前的都是iso8859-1
编码过滤器
package com.wangxing.filter;
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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CharEncoderFilter implements Filter{
//定义一个保存字符编码的变量
private String myencode = "utf-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化字符过滤器");
//获取提前在web.xml文件中配置好的参数
myencode = filterConfig.getInitParameter("myencode");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//每接收一次请求对字符编码进行处理
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpResp = (HttpServletResponse) response;
//设置请求和响应的字符编码
httpReq.setCharacterEncoding(this.myencode);
httpResp.setCharacterEncoding(this.myencode);
//解决post请求的中文乱码
//设置响应头文本输出类型
httpResp.setContentType("text/html;charset="+this.myencode);
//解决get请求的中文乱码问题--需要重写getParameter(arg0)
//getParameter(arg0)方法是用来获取url地址栏的name=value,
//重写这个方法,对获取的value值进行编码转换最后返回转好的数据
//创建重写的类
CharacterRequest charReq = new CharacterRequest(httpReq, this.myencode);
//将重写的处理请求类,和设置好字符编码的响应类传递给目标资源
chain.doFilter(charReq, httpResp);
}
@Override
public void destroy() {
System.out.println("字符过滤器被销毁");
}
}
对 request 进行包装
package com.wangxing.filter;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* 处理请求以及获得参数
* 重写了getParameter(String name)方法
* 对获取的查询字段的值进行重新编码
* 这是一个继承了HttpServletRequestWrapper类的子类
* HttpServletRequestWrapper类实现了HttpServletRequest接口
* @author 14336
*
*/
public class CharacterRequest extends HttpServletRequestWrapper{
private HttpServletRequest request;
private String encoding="utf-8";
public CharacterRequest(HttpServletRequest request,String encoding) {
super(request);
this.request = request;
this.encoding = encoding;
}
@Override
public String getParameter(String name) {
String value = request.getParameter(name);
if (value == null) {
return null;
}
//得到请求的提交方式
/*equalsIgnoreCase(String)
* 将此字符串与另一个字符串进行比较,忽略大小写考虑。
* 如果两个字符串长度相同,
* 且两个字符串中对应的字符具有相同的忽略大小写,
* 则认为两个字符串具有相同的忽略大小写。
* */
String method = request.getMethod();
if ("get".equalsIgnoreCase(method)) {
//tomcat8以后默认编码格式是 utf-8; 7之前的都是iso8859-1
try {
//变量指向对象
value = new String(value.getBytes(this.encoding),this.encoding);
} catch (UnsupportedEncodingException e) {
// TODO 自动生成的 catch 块
//抛出一个运行时异常
throw new RuntimeException(e);
}
}
//若提交方式不是get则直接返回value
return value;
}
}
测试类:
package com.wangxing.servlet;
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 TestServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("MyTestServlet----");
String myname=req.getParameter("myname");
System.out.println("myname=="+myname);
PrintWriter out=resp.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset=\"UTF-8\">");
out.println("<title></title>");
out.println("</head>");
out.println("<body>");
out.println("<center>");
out.write("Hello MyServlet==myname=="+myname);
out.println("<h1>被访问的目标资源</h1>");
out.println("</center>");
out.println("</body>");
out.println("</html>");
out.close();
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<filter>
<filter-name>test</filter-name>
<filter-class>com.wangxing.filter.CharEncoderFilter</filter-class>
<init-param>
<param-name>myencode</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>test</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>com.wangxing.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
</web-app>
http://127.0.0.1:8080/TestFilter3_0320/test?myname=%E5%BC%A0%E4%B8%89