1.创建过滤器
过滤器对象放置在javax.servlet包中,其名称为Filter,它是一个接口。除了这个接口外,与过滤器相关的对象还有FilterConfig对象与FilterChain对象,这个两个对象同样是接口,位于javax.servlet包中,分别为过滤器的配置对象与传递对象。实际开发中,定义过滤器只需要实现Filter接口即可,见下图

Filter接口:每一个过滤器对象都要直接或间接地实现Filter接口,在Filter接口中定义了3个方法,分别为init()方法、doFilter()方法和destroy()方法,其方法声明及说明如下表所示。
Filter接口的方法声明及说明
| 方法声明 | 说明 |
| public void init(FilterCofig filterConfig)throws ServletException | 过滤器初始化方法,该方法在过滤器初始化时调用 |
| public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throw IOException,ServletException | 对请求进行过滤处理 |
| public void destroy() | 销毁方法,以便释放资源 |
FilterConfig接口的方法声明及说明
| 方法声明 | 说明 |
| public String getFilterName() | 用于获取过滤器的名字 |
| public ServletContext getServletContext() | 获取Servlet上下文 |
| public String getInitParameter(String name) | 获取过滤器的初始化参数值 |
| public Enumeration getInitParameterNames() | 获取过滤器的所有初始化参数 |
FilterChain接口仍然由Servlet容器进行实现,在这个接口中只有一个方法,其方法声明如下:
public void doFilter(ServletRequest request,ServletResponse response)throws IOException,ServletException
该方法用于将过滤后的请求传递给下一个过滤器,如果此过滤器已经是过滤器链中的最后一个过滤器,那么,请求将传递给目标资源
【案例6-1】创建名为MyFilter的过滤器对象。
package ch6;
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 MyFilter implements Filter{
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("初始化处理");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("过滤处理");
chain.doFilter(request, response);//向下传递过滤器
}
@Override
public void destroy() {
System.out.println("释放资源");
}
}
过滤器处理的业务逻辑需要编写到doFilter()方法中,在请求过滤处理后,需要调用chain参数的doFilter()方法将请求向下传递给下一过滤器或者目标资源。
2.配置过滤器
配置Servlet过滤器包括下面两个步骤:
(1)命名Servlet过滤器和指定Servlet过滤器相应的实现类,并且可选择指定传递至Servlet过滤器的初始化参数。配置代码如下:
<filter>
<filter-name>FilterName</filter-name>
<filter-class>package.className </filter-class>
<init-param>
<param-name>ParamName1</param-name>
<param-value>ParamValue1</param-value>
</init-param>
<init-param>
<param-name>ParamName2</param-name>
<param-value>ParamValue2</param-value>
</init-param>
</filter>
FilterName是过滤器的名称,package.className是过滤器的实现类,<init-param>是可选的元素,用来给过滤器提供初始化参数,过滤器可包含多个<init-param>子元素。
(2)将Servlet 过滤器映射至URL或 Servlet,这是通过<filter-mapping>元素来实现的。将Servlet 过滤器映射至 URL的配置代码如下:
<filter-mapping>
<filter-name>FilterName</filter-name>
<url-pattern>/path</url-pattern>
</filter-mapping>
<filter-name>元素和上面<filter>元素的子元素<filter-name>一致。<url-pattern>元素指定了过滤器的映射路径,Servlet过滤器还可以映射至Servlet:
<filter-mapping>
<filter-name>FilterName</filter-name>
<servlet-name>ServletName</servlet-name>
</filter-mapping>
<filter-name>元素和<filter>元素的子元素<filter-name>一致。<servlet-name>元素指定过滤器映射的Servlet的名称。
【案例6-2】配置MyFilter过滤器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>ch6.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/MyFilter</url-pattern>
</filter-mapping>
</web-app>
【案例6-3】创建一个过滤器实现网站访问计数器的功能,并在配置文件将网站访问量的初始值设置为1000。
package ch6;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class CountFilter implements Filter {
// 来访数量
private int count;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 获取初始化参数
String param = filterConfig.getInitParameter("count");
// 将字符串转换为int
count = Integer.valueOf(param);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 访问数量自增
count ++;
// 将ServletRequest转换成HttpServletRequest
HttpServletRequest req = (HttpServletRequest) request;
// 获取ServletContext
ServletContext context = req.getSession().getServletContext();
//将访问数量值放入ServletContext中
context.setAttribute("count", count);
//向下传递过滤器
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
配置文件web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<!-- 过滤器声明 -->
<filter>
<!-- 过滤器的名称 -->
<filter-name>CountFilter</filter-name>
<!-- 过滤器的完整类名 -->
<filter-class>ch6.CountFilter</filter-class>
<!-- 设置初始化参数 -->
<init-param>
<!-- 参数名 -->
<param-name>count</param-name>
<!-- 参数值 -->
<param-value>1000</param-value>
</init-param>
</filter>
<!-- 过滤器映射 -->
<filter-mapping>
<!-- 过滤器名称 -->
<filter-name>CountFilter</filter-name>
<!-- 过滤器URL映射 -->
<url-pattern>/example/ch6/count.jsp</url-pattern>
</filter-mapping>
</web-app>
页面文件count.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>人数统计</title>
</head>
<body>
<h2>
欢迎光临,<br>
您是本站的第【
<%=application.getAttribute("count") %>
】位访客!
</h2>
</body>
</html>
效果图如下:

3.字符编码过滤器
在Java Web程序开发中,由于Web容器内部所使用编码格式并不支持中文字符集,所以,处理浏览器请求中的中文数据,就会出现乱码现象,如图所示。

在实际开发过程中,如果通过在每一个业务处理中指定中文字符集编码,操作过于烦琐,而且容易遗漏某一个业务中的字符编码设置。如果通过过滤器来处理字符编码,就可以做到简单又万无一失,如下图所示:

在Web应用中部署了字符编码过滤器后,即使Web容器的编码格式不支持中文,但浏览器的每一次请求都会经过过滤器进行转码,所以也就完全避免了中文乱码现象的产生。
【案例6-4】创建字符编码过滤器,避免中文乱码现象的产生。
package ch6;
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 CharactorFilter implements Filter {
// 字符编码
String encoding = null;
@Override
public void destroy() {
encoding = null;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 判断字符编码是否为空
if(encoding != null){
// 设置request字符编码
request.setCharacterEncoding(encoding);
// 设置response字符编码
response.setContentType("text/html; charset="+encoding);
}
// 传递给下一过滤器
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 获取初始化参数
encoding = filterConfig.getInitParameter("encoding");
}
}
CharactorFilter的配置代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<!--声明过滤器-->
<filter>
<!-- 过滤器名称 -->
<filter-name>CharactorFilter</filter-name>
<!-- 过滤器的完整类名 -->
<filter-class>ch6.CharactorFilter</filter-class>
<!-- 初始化参数 -->
<init-param>
<!-- 参数名 -->
<param-name>encoding</param-name>
<!-- 参数值 -->
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!-- 过滤器映射 -->
<filter-mapping>
<!-- 过滤器名称 -->
<filter-name>CharactorFilter</filter-name>
<!-- URL映射 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
在过滤器CharactorFilter的配置声明中,它的初始化参数encoding的值为UTF-8,它与JSP页面的编码格式相同,支持中文。过滤器的URL映射可以使用正则表达式进行配置,本例中使用“/*”来匹配所有请求。

