监听器(Listener)
**理解:**监听器就是对项目起到监听的作用,它能感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化;
web监听器是Servlet中一种特殊的类,能监听web中的特定时间,比如ServletContext,HttpSession,ServletRequest的创建和销毁;变量的创建、销毁和修改等。可以在某些动作前后增加处理,实现监控。
监听器就是一个实现特定接口的普通Java程序,这个程序专门用于监听一个Java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。
1、 监听器接口和注册
监听器接口主要在 javax.servlet 和 javax.servlet.http 的包中。对应上文的三类,有以下这些接口:
第一类:
名称 | 作用 |
---|---|
javax.servlet.ServletContextListener | 它能响应Servlet生命周期事件,它提供了ServletContext创建之后和ServletContext关闭之前的会被调用的方法。 |
javax.servlet.http.HttpSessionListener | 它能响应HttpSession的创建、超时和失效事件。 |
javax.servlet.http.HttpActivationListener | 它在一个HttpSession激活或者失效时被调用。 |
javax.servlet.ServletRequestListener | 它能响应一个ServletRequest的创建或删除。 |
第二类:
名称 | 作用 |
---|---|
javax.servlet.ServletContextAttributeListener | 它能响应ServletContext范围内的属性添加、删除、替换事件。 |
javax.servlet.http.HttpSessionAttributeListener | 它能响应HttpSession范围内的属性添加、删除、替换事件。 |
javax.servlet.http.HttpSessionBindingListener | 可以实现这个接口来保存HttpSession范围的属性。当有属性从HttpSession添加或者删除时,它能做出响应。 |
javax.servlet.ServletRequestListener | 它能响应ServletRequest范围的属性添加、删除、修改事件。 |
2、Listener部署
编写一个监听器,只需要写一个Java类来实现对应的监听器接口就可以了。在Servlet 3.0和Servlet 3.1中提供了两种注册监听器的方法。一种是使用WebListener注解。例如:
@WebListener
public class ListenerClass implements ListenerInterface {
}
第二种是在部署描述文档中增加一个listener元素。
<listener>
<listener-class>fully-qualified listener class</listener-class>
</listener>
3、listener实际应用
- 统计在线人数,利用HttpSessionLisener
- 加载初始化信息:利用ServletContextListener
- 统计网站访问量、实现访问监控等
获取当前在线人数
package com.mycompany.mvc.listener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class myHttpSessionListener implements HttpSessionListener{
public static int peopleOnLine = 0;
@Override
public void sessionCreated(HttpSessionEvent hse) {
System.out.println("myHttpSessionListener.sessionCreated():"+hse);
peopleOnLine++;
hse.getSession().setAttribute("peopleOnLine",peopleOnLine);
}
@Override
public void sessionDestroyed(HttpSessionEvent hse) {
System.out.println("myHttpSessionListener.sessionDestroyed():"+hse);
peopleOnLine--;
hse.getSession().setAttribute("peopleOnLine",peopleOnLine);
}
}
<%=session.getAttribute("peopleOnLine")%>
过滤器(Filters)
过滤器是Servlet的高级特性之一,也别把它想得那么高深,只不过是实现Filter接口的Java类罢了!
当浏览器发送请求给服务器的时候,先执行过滤器,然后才访问Web的资源。服务器响应Response,从Web资源抵达浏览器之前,也会途径过滤器。。
过滤器可以比喻成一张滤网。我们想想现实中的滤网可以做什么:在泡茶的时候,过滤掉茶叶。那滤网是怎么过滤茶叶的呢?规定大小的网孔,只要网孔比茶叶小,就可以实现过滤了!
引申在Web容器中,过滤器可以做:过滤一些敏感的字符串【规定不能出现敏感字符串】、避免中文乱码【规定Web资源都使用UTF-8编码】、权限验证【规定只有带Session或Cookie的浏览器,才能访问web资源】等等等,过滤器的作用非常大,只要发挥想象就可以有意想不到的效果
过滤器其实也是责任链模式的一种实现,FilterChain层层往下执行,直到最后没有过滤器,就到了「目标资源」
**理解:**就是对请求起到过滤的作用,它在监听器之后,作用在servlet之前,对请求进行过滤;
1、Filter API
Filter的实现必须继承 javax.servlet.Filter 接口。这个接口包含了 Filter 的三个生命周期:init,doFilter,destroy。
Servlet容器初始化 Filter 时,会触发 Filter 的 init 方法,一般在应用开始时,而不是在相关资源使用时才初始化,这个方法只调用一次。init 定义如下:
void init(FilterConfig filterConfig)
当Servlet 容器每次处理Filter相关资源时,都会调用该Filter实例的doFilter方法。doFilter包含三个参数,定义如下:
void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
在doFilter中可以访问ServletRequest、ServletResponse。
在Filter的doFilter的实现中,最后一行需要调用FilterChain 中的 doFilter 方法。注意Filter的doFilter方法里的第三个参数,就是filterChain的实例:
filterChain.doFilter(request, response)
2、Filter部署
第一种方式:在web.xml文件中配置
<filter>
//用于为过滤器指定一个名字,该元素的内容不能为空。
<filter-name>FilterDemo1</filter-name>
//元素用于指定过滤器的完整的限定类名。
<filter-class>FilterDemo1</filter-class>
</filter>
//<filter-mapping>元素用于设置一个Filter 所负责拦截的资源
<filter-mapping>
//用于设置filter的注册名称。该值必须是在元素中声明过的过滤器的名字
<filter-name>FilterDemo1</filter-name>
//设置 filter 所拦截的请求路径(过滤器关联的URL样式)
<url-pattern>/*</url-pattern>
</filter-mapping>
第二种方式:通过注解配置
@WebFilter(urlPatterns = {"*.jsp","*.do"})
2.1 Filter的配置详解
- 具体的资源路径
/index.jsp
只有访问index.jsp的时候,过滤器才会被执行
- 拦截目录
/user/*
访问/user目录下的所有资源的时候,过滤器才会被执行
- 后缀名拦截
*.jsp
访问所有jsp页面都会被拦截
- 拦截所有资源
/*
3、Filter实际应用
一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤……
编码过滤器(解决乱码的问题)
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("-----filterEncoding dofillter----");
//将request和response强转成http协议的
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=UTF-8");
// 放行,转到下一个过滤器
filterChain.doFilter(request, response);
}