过滤器
Servlet过滤器可以对Servlet、JSP和HTML文件过滤。
过滤器在实际开发中用得较多,是属于较重点的内容。
主要是处理session信息,登陆请求。也可以启动框架内部的某些。
Servlet过滤器的概念
Servlet过滤器是在Java Servlet规范2.3中定义的,它能够对Servlet容器的请求和响应对象进行检查和修改。
Servlet过滤器本身并不生成请求和响应对象,它只提供过滤作用。
Servlet过滤器能够在Servlet被调用之前检查Request对象,修改Request Header和Request内容。
在Servlet被调用之后检查Response对象,修改Response Header和Response内容。
Servlet过滤器负责过滤的Web组件可以是Servlet、JSP或HTML文件。
Servlet过滤器的过滤过程
过滤器的处理过程是一个链式的过程(FilterChain),即多个过滤器组成一个链,依次处理,最后交给过滤器之后的资源。
其中链式过滤过程中也可以直接给出响应,即返回,而不是向后传递。
Filter接口
所有的Servlet过滤器类都必须实现javax.servlet.Filter接口。
这个接口含有3个过滤器类必须实现的方法:
init(FilterConfig):这是Servlet过滤器的初始化方法,Servlet容器创建Servlet过滤器实例后将调用这个方法。
在这个方法中可以读取web.xml文件中Servlet过滤器的初始化参数。
比如web.xml中声明:
<filter>
<filter-name>MyFilter1</filter-name>
<filter-class>com.mengdd.filter.MyFilter1</filter-class>
<init-param>
<param-name>hello</param-name>
<param-value>world</param-value>
</init-param>
<init-param>
<param-name>name</param-name>
<param-value>zhang</param-value>
</init-param>
</filter>
在MyFilter1中:
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String paramValue1 = filterConfig.getInitParameter("hello");
String paramValue2 = filterConfig.getInitParameter("name");
ServletContext context = filterConfig.getServletContext();
}
注意:一旦一个过滤器启动失败,会导致整个Web应用启动失败。
doFilter(ServletRequest, ServletResponse, FilterChain):这个方法完成实际的过滤操作。
当客户请求访问与过滤器关联的URL时,Servlet容器将先调用过滤器的doFilter方法。
FilterChain参数用于访问后续过滤器。
在这个方法中调用chain.doFilter()方法,用于调用过滤器链中后续过滤器的doFilter()方法,假如没有后续过滤器,那么就把客户请求传给相应的Web组件。
如果在这个方法中没有调用chain.doFilter()方法,客户请求不会到达所访问的Web组件。
destroy():Servlet容器在销毁过滤器实例前调用该方法,在这个方法中可以释放Servlet过滤器占用的资源。
过滤器的例子
比如用户登录之后,将信息传入session中,之后的其他页面入口可能需要 检测是否存在session,以避免直接在地址栏输入地址访问页面而造成的session中没有用户信息的情况,如果在每个Servlet或JSP前面都 要判断session中是否有相应属性,会有很多的代码重复,用过滤器可以很好地解决这个问题,如果不含登录信息,即转向到用户登录页面。
package com.mengdd.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;
import javax.servlet.http.HttpSession;
public class LoginFilter implements Filter {
@Override
public void destroy() {
// 由Web容器调用
// 在这里进行资源释放
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter invoked!");
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();// 获取请求的session,如果没有,会创建一个新的session
// 对不需要进行过滤的请求进行事先筛选操作
String requestURI = req.getRequestURI();
if (requestURI.endsWith("login.jsp")
|| requestURI.endsWith("LoginServlet")) {
chain.doFilter(request, response);
return;
}
if (null == session.getAttribute("username")) {
// session中没有用户名属性,说明是新的session,之前没有登录
// 用过滤器完成了整个Web应用中未登录情况的处理
((HttpServletResponse) response).sendRedirect("login.jsp");
// 这里注意,由于本filter配置的<url-pattern>/*</url-pattern>是针对所有地址的
// 所以请求发送到login.jsp页面也会需要先经过此过滤器,造成重定向的递归重复调用
// 所以需要对请求的URI进行判断
}
else {
// 按照过滤链继续往下走
chain.doFilter(request, response);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("Filter init");
// 过滤器是非常特殊的一个Servlet,它会在容器启动的时候得到初始化
// 过滤器的启动失败会导致Web应用启动失败
}
}
过滤器的配置和Servlet的配置相似,只不过URL配置的是要过滤请求的URL:
<!-- filter一般配置在所有的Servlet上面 -->
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.mengdd.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- /*表示所有地址,即所有请求都会被送到这个过滤器 -->
可以做很多练习例子,比如可以创建一个NoteFilter过滤器,它可以拒绝列在黑名单上的客户访问留言簿。(黑名单通过过滤器参数设置)。
也可以利用Filter进行一些关键词修改替换的工作。
串联过滤器的例子
几点说明:
1.串联过滤器的顺序是按照在web.xml中的配置顺序为准的。
<filter>
<filter-name>MyFilter1</filter-name>
<filter-class>com.mengdd.filter.MyFilter1</filter-class>
<init-param>
<param-name>hello</param-name>
<param-value>world</param-value>
</init-param>
<init-param>
<param-name>name</param-name>
<param-value>zhang</param-value>
</init-param>
</filter>
<filter>
<filter-name>MyFilter2</filter-name>
<filter-class>com.mengdd.filter.MyFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter1</filter-name>
<url-pattern>/InfoServlet</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>MyFilter2</filter-name>
<url-pattern>/InfoServlet</url-pattern>
</filter-mapping>
2.在Servlet过滤器中能访问application范围内的共享数 据:先调用FilterConfig的getServletContext()方法获得ServletContext,再调用 ServletContext的getAttribute()方法来获得application范围内的共享数据。
package com.mengdd.filter;
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;
public class MyFilter1 implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("MyFilter1 --> doFilter invoked!");
System.out.println("MyFilter1 --> before chain.doFilter()");
chain.doFilter(request, response);
System.out.println("MyFilter1 --> after chain.doFilter()");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String paramValue1 = filterConfig.getInitParameter("hello");
String paramValue2 = filterConfig.getInitParameter("name");
ServletContext context = filterConfig.getServletContext();
}
}
package com.mengdd.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 MyFilter2 implements Filter{
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("MyFilter2 --> doFilter invoked!");
System.out.println("MyFilter2 --> before chain.doFilter()");
chain.doFilter(request, response);
System.out.println("MyFilter2 --> after chain.doFilter()");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
参考资料
圣思园张龙老师Java Web视频教程。