1.Filter接口的三个方法
javax.servlet.Filter接口是Servlet的过滤器,它是Servlet 2.3规范中新增加的一个功能,主要用于完成一些通用的操作,如编码的过滤、判断用户的登录状态等。是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在Servlet 进行响应处理的前后实现一些特殊功能。它是部署在服务器上运行的。
当用户通过浏览器访问服务器中的目标资源时,首先会被 Filter 拦截,在 Filter 中进行预处理操作,然后再将请求转发给目标资源。当服务器接收到这个请求后会对其进行响应,在服务器处理响应的过程中,也需要将响应结果经过滤器处理后,才发送给客户端。
在 javax.servlet.Filter 接口中定义了三个方法
1.init(FilterConfig filterConfig)用于初始化过滤器。我们可以将在程序运行最初阶段的一些操作定义在初始化方法中来实现。
2.doFilter(ServletRequest request,ServletResponse response, FilterChain chain)实现对请求和响应对象进行过滤操作。我们可以将对请求和响应信息过滤的操作定义在该方法中来实现。
3.destroy()用于释放被 Filter 对象打开的资源。我们可以将关闭数据库和 I/O 流的动作定义在该方法中实现。
表中的三个方法都是可以表现 Filter 生命周期的方法,其中 init() 方法在 Web 应用程序加载时会被调用,destroy() 方法在 Web 应用程序卸载(或关闭)时被调用,这两个方法都只会被调用一次,而 doFilter() 方法会被调用多次(只要客户端有请求时就会被调用),过滤器所有的工作集中在 doFilter() 方法中。
注意:过滤器的配置需要在servlet的配置前面
下面通过案例演示 Filter 程序如何对 Servlet 程序的调用过程进行拦截。
public class demoFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter过滤器初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤请求和响应");
}
@Override
public void destroy() {
System.out.println("销毁过滤器");
}
}
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("---------------Servlet");
}
}
可以直接对客户端作出响应,不放行到servlet
对请求进行放行:
doFilter(ServletRequest request,ServletResponse response, FilterChain chain)
此方法三个参数,第三个参数注意!!!
多个过滤器按照web.xml配置顺序执行
2.过滤器链—FilterChain
在一个 Web 应用程序中可以注册多个过滤器程序,每个过滤器程序都可以针对某一个 URL 进行拦截。如果多个过滤器程序都对同一个URL进行拦截,那么这些过滤器就会组成一个过滤器链--FilterChain
FilterChain接口中只有一个doFilter(ServletRequest req,ServletResponse resp)方法,该方法的作用是让过滤器链上的当前过滤器放行,使请求进入下一个过滤器,直至目标资源。
在上图中,当浏览器访问 Web 服务器中的资源时,需要经过两个过滤器 Filter1 和 Filter2。首先 Filter1 会对这个请求进行拦截,在 Filter1 中处理完请求后,通过Filter 链 FilterChain 对象调用 doFilter() 方法将请求传递给 Filter2,Filter2 处理用户请求后同样FilterChain 对象调用 doFilter() 方法,最终将请求发送给目标资源。当 Web 服务器对这个请求做出响应时,也会被过滤器拦截,但这个拦截顺序与之前相反,最终将响应结果发送给客户端浏览器。
3.初始化中的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>的初始化值。
4.Filter三种映射方式
4.1 使用通配符*拦截用户的所有请求
对<url-pattern>进行配置
当访问test2的时候,过滤器1和2都会执行
4.2 拦截不同方式的访问请求
在 web.xml 文件中,每一个 <filter-mapping> 元素都可以配置一个 Filter 所负责拦截的资源。在 <filter-mapping> 元素中有一个特殊的子元素 <dispatcher>,该元素用于指定过滤器所拦截的资源被 Servlet 容器调用的方式。
可以在一个<filter-mapping>元素中加入任意数目的<dispatcher>,使得filter将会作用于直接从 客户端过来的request,通过forward过来的request,通过 include过来的request和通过<error-page>过来的request。如果没有指定任何< dispatcher >元素,默认值是REQUEST。
<dispatcher>的取值有4种:
REQUEST ---直接从客户端传递过来的,则必须经过这个过滤器
FORWARD---通过RequestDispatcher的forward方法传递过来,则必须经过这个过滤器
INCLUDE---通过RequestDispatcher的include方法传递过来,则必须经过这个过滤器
ERROR---通过<error-page>过来的,则必须经过这个过滤器
4.3 拦截不同访问路径的访问请求
通过设置<filter-mapping> 元素中的<url-pattern>指定不同的访问路径,来确定哪些资源可以访问当前过滤器,哪些资源不可以访问当前过滤器。
5. ServletFilter统一编码,解决中文乱码问题
tomcat8以后默认编码格式是utf-8;7之前的都是iso8859-1。
之前写Servlet程序时,为了防止中文乱码总是需要设置
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
但是如果这个Servlet程序多的时候,可能会忘记设置字符编码。
因此设置过滤器,在过滤器中解决乱码问题。
public class CharFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
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 {
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();
}
}
缺点:如果需要更改编码格式呢?就需要在filter文件中更改,源代码改变不好,如果拿不到源代码呢???
改进:在web.xml中的filter中配置<init-param>,在过滤器的初始化中加载
6.解决发送请求的参数乱码
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Archetype Created Web Application</display-name>
<filter>
<filter-name>charfilter</filter-name>
<filter-class>com.weiwei.filter.CharFilter</filter-class>
<init-param>
<param-name>charcode</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>com.weiwei.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
</web-app>
TestServlet类
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 {
String name = req.getParameter("name");
System.out.println(name);
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();
}
}
CharacterRequest类
public class CharacterRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
private String encoding ;
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;
}
//得到请求方式
String method = request.getMethod();
if ("get".equalsIgnoreCase(method)) {
try {
value = new String(value.getBytes(this.encoding), this.encoding);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return value;
}
}
Filter类
public class CharFilter implements Filter {
private String code;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
code = filterConfig.getInitParameter("charcode");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp= (HttpServletResponse) servletResponse;
req.setCharacterEncoding(code);
resp.setCharacterEncoding(code);
filterChain.doFilter(servletRequest,servletResponse);
//解决post请求的中文乱码
resp.setContentType("text/html;charset"+code);
//解决get请求的中文乱码----重写getParameter方法
CharacterRequest characterRequest = new CharacterRequest(req, code);
filterChain.doFilter(characterRequest,resp);
}
@Override
public void destroy() {
}
}