过滤器和监听器
1.过滤器
1.1)简介
过滤器也称之为拦截器,是Servlet2.3规范中新增的功能,在servlet2.4规范中得到了增强。过滤器是servlet中非常实用的技术,可以在用户访问某个web资源之前,对访问的请求和响应进行拦截,从而实现一些特殊的功能。例如:验证用户访问权限,记录用户操作,对请求进行重新编码和压缩响应信息等。
原理:当用户的请求到达请求的资源之前,可借助过滤器来改变一些请求的内容,此过程叫做预处理。当执行结果返回到用户之前,可经过过滤器来修改响应,这个叫后处理。过滤器运行过程中有一下步骤;
- Web容器判断请求的资源是否有相匹配的过滤器,如果有,就交。
- 过滤器进行预处理,完事儿发给目标资源
- 目标资源对请求做出响应
- 容器将响应返回给过滤器
- 过滤器进行后处理
- Web容器将响应发回客户端
在一个web应用中,可以创建多个过滤器,形成过滤器连=链,每一个都有特殊的功能。在请求响应的过程中,并不需要经过所有的过滤器链,而是根据过滤器链中每个过滤器的条件来匹配需要过滤的资源。
1.2)过滤器核心接口
1.Filter接口
Filter定义了三个方法
方法 | 描述 |
Init(Filter config) | 过滤器的初始化方法 |
doFilter(request,response,FilterChain chain) | 过滤器功能实现 |
destroy() | 生命周期结束时由web容器调用,释放资源 |
过滤器的生命周期分为4个阶段。
- 加载和实例化。
Web启动的时候会根据@WebFilter属性的filterName所定义的类名的字符拼写顺序,或者web.xml中声明的filter顺序依次实例化Filter
- 初始化
Web容器调用init()方法来初始化过滤器 该方法传入一个Filterconfig对象,初始化只进行一次。
- doFilter()方法的执行
当客户端请求目标资源的时候,容器会根据@WebFilter属性的filterName指定的过滤器依次调用相应的过滤器。的doFilter方法。在这个链式的过程中,可以调用FilterChain对象的doFilter()方法将请求发给下一个过滤器或者目标资源,或者直接响应,或者请求转发到其他资源。。过滤器的使用不依赖于协议,,请求响应参数是ServletRequest和ServletResponse
- 销毁
Web容器调用destroy()方法指示过滤器的声明周期结束。在这个方法中可以释放过滤器使用的资源。
2.FilterConfig接口
容器将实例作为参数传入过滤器对象的初始化方法init()中,来获取过滤器的初始化参数和Servlet的相关信息。
方法 | 描述 |
getFilterName() | 获取配置信息中指定的过滤器名字 |
getInitParameter(String name) | 获取配置信息中指定的名为name的过滤器初始化参数值 |
geiInitParameterNames() | 获取过滤器的所有初始化参数的名字的枚举集合 |
getServletContext() | 获取Servlet上下文集合 |
3.FilterChain接口
该接口由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()方法中。过滤器对象使用FilterChain对象调用过滤器链中的下一个过滤器,如果该过滤器是链中最后一个过滤器,那么将调用目标资源。
doFilter(ServletRequest request,ServletResponse response) 该方法将使用过滤器链中的下一个过滤器被调用,如果是最后一个过滤器,则调用目标资源。
1.3)过滤器的开发
- 创建一个Filter接口的实现类
Eclipse中 New--->Filter,eclipse会自动创建,init、doFilter()、destroy 方法,这是Filter的必备条件
2.编写过滤器功能代码
下面过个实现一个对请求和响应过程计时的功能。
import java.io.IOException;
import java.util.Date;
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.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
@WebFilter(urlPatterns = {"/*"}, initParams = {@WebInitParam(name = "param", value = "xxxxx")})
public final class ExampleFilter implements Filter {
private String attribute = null;
private FilterConfig filterConfig = null;
public void init(FilterConfig fConfig) throws ServletException {
this.filterConfig = fConfig;
this.attribute = fConfig.getInitParameter("param");
filterConfig.getServletContext().log(
"获得初始化参数param的值为:" + this.attribute);
}
@Override
public void destroy() {
this.attribute = null;
this.filterConfig = null;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
long startTime = System.currentTimeMillis();
filterConfig.getServletContext().log(
new Date(startTime) + "请求经过" + this.getClass().getName()
+ "过滤器");
chain.doFilter(request, response);
long stopTime = System.currentTimeMillis();
filterConfig.getServletContext().log(
new Date(stopTime) + "响应经过" + this.getClass().getName()
+ "过滤器,本次请求响应过程花费 " + (stopTime - startTime) + " 毫秒");
}
}
3.对过滤器进行声明配置
@WebFilter(urlPatterns = {“/*”},initParams = {@WebInitParam(name = “param”,value = “xxxx”)})
上面代码用于将一个类声明为Filter,同时进行属性配置,改配置表示对本应用的所有请求使用此过滤器进行过滤拦截,同时在过滤器初始化时传递初始化参数param。
Filter常用的属性如下:
方法 | 描述 |
FilterName | Filter的名称,默认类名 |
urlPatterns | 必有的属性,指所拦截的url |
ServletName | 用于指定对那些servlet进行过滤 |
dispatcherTypes | 用于指定该Filter对那些模式的请求进行过滤 |
1.4)过滤器的应用
过滤器有很多实用的技术,也得到了广泛的使用。
- 做统一认证处理
- 对用户的请求进行检查和更精确的记录
- 监听或对用户所传递的参数做前置处理,如防止数据注入攻击
- 改变图像文件的格式
- 对请求和响应进行编码
- 对响应做压缩处理
- 对xml的输出使用XSLT来转换
- 批量设置请求编码
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 SetCharacterEncodingFilter implements Filter {
String encoding;
public SetCharacterEncodingFilter() {
}
public void init(FilterConfig fConfig) throws ServletException {
// 获取过滤器配置的初始参数
this.encoding = fConfig.getInitParameter("encoding");
}
public void destroy() {
this.encoding = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (encoding == null)
encoding = "UTF-8";
// 设置请求的编码
request.setCharacterEncoding(encoding);
// 过滤传递
chain.doFilter(request, response);
}
}
- 控制用户访问权限
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.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* 控制用户对某些请求地址的访问权限
*/
@WebFilter(urlPatterns = { "/*" }, initParams = {
@WebInitParam(name = "loginPage", value = "login.jsp"),
@WebInitParam(name = "loginServlet", value = "LoginProcessServlet") })
public class SessionCheckFilter implements Filter {
// 用于获取初始化参数
private FilterConfig config;
public SessionCheckFilter() {
}
public void init(FilterConfig fConfig) throws ServletException {
this.config = fConfig;
}
public void destroy() {
this.config = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 获取初始化参数
String loginPage = config.getInitParameter("loginPage");
String loginServlet = config.getInitParameter("loginServlet");
// 获取会话对象
HttpSession session = ((HttpServletRequest) request).getSession();
// 获取请求资源路径(不包含请求参数)
String requestPath = ((HttpServletRequest) request).getServletPath();
if (session.getAttribute("user") != null
|| requestPath.endsWith(loginPage)
|| requestPath.endsWith(loginServlet)) {
// 如果用户会话域属性user存在,并且请求资源为登录页面和登录处理的Servlet,则“放行”请求
chain.doFilter(request, response);
} else {
// 对请求进行拦截,返回登录页面
request.setAttribute("tip", "您还未登录,请先登录!");
request.getRequestDispatcher(loginPage).forward(request, response);
}
}
}
2.监听器
2.1)简介
Servlet API提供了大量监听器接口来帮助开发者实现对web应用内特定事件进行监听从而当web应用内这些特定事件发生时,回调监听器内的事件监听器方法来实现一些功能。
实现监听器需要通过两个步骤:
【步骤一】
定义监听器类,实现监听器接口的所有方法
【步骤二】
通过Annotation或者在web.xml文件中声明Listener
创建Listener时,需要使用@WebListener对监听进行声明,注解@WebListener的常用属性如下:
@WebListener(“描述信息”)
2.2)与servlet上下文相关的监听器
监听器接口名称 | 说明 |
ServletContextListener | 用于监听ServletContext对象的创建和销毁 |
ServletContextAttributeListener | 用于监听ServletContext范围内属性的改变 |
1.ServletContextListener
- contextInialized(ServletContextEvent sce)当servletContext对象创建时,web容器将调用此方法。该方法接受ServletContextEvent事件对象,通过此对象可获得当前被创建的ServletContext对象,通过此对象可获得当前被创建的ServletContext对象
- contextDestroyed(ServletContextEvent sce)当ServletContext对象被销毁是执行
2.ServletContextAttributeListener
- attributeAdded(ServletContextAttributeEvent event)当程序把一个属性存入到application中时执行此方法
- attributeRemoved(ServletContextAttributeEvent event)当程序把一个属性从application范围中删除时
- attributeReplaced(ServletContextAttributeEvent event)当程序替换application范围内的属性时。
2.3)与会话相关的监听器
监听器接口 | 说明 |
HttpSessionListener | 用于监听会话对象的创建和销毁 |
HttpSessionAttributeListener | 用于监听会话域内属性的改变 |
1.HttpSessionListener
- sessionCreated(HttpSessionEvent event)当HttpSession对象被创建时,web容器调用此方法
- sessionDestroyed(HttpSessionEvent se)当httpsession被销毁时,执行该代码
2.HttpSessionAttributeListener
- AttributeAdded(HttpSessionAttributeEvent event)当程序把一个属性存入session范围时
- AttributeRemoved(HttpSessionAttributeEvent event)当属性从session中删除时
- AttributeReplaced(HttpSessionAttributeEvent event)当程序替换session范围中的属性时
2.4)与请求相关的监听器
监听器接口 | 说明 |
ServletRequestListener | 用于监听用户请求的产生和结束 |
ServletRequestAttributeListener | 用于监听ServletRequest(requset)范围内的属性 |
1.ServletRequestListener
- requestInitialized(ServletRequestEvent event)当ServletRequest对象被创建时
- RequestDestroyed(ServletRequsetEvent event)当ServletResquset对象被销毁时
2.ServletRequestAttributeListener
- arributeAdded(ServletRequestAttributeEvent event)当程序把一个属性存入requset范围中时
- attributeRemoved(ServletRequestAttributeEvent event)当程序吧一个属性从request范围中删除时。
- attributeReplaced(ServletRequestAttributeEvent event)当程序替换一个属性时