Listener 监听器
-
能做什么事?
监听某一个事件的发生。 状态的改变。 -
监听器的内部机制
其实就是接口回调.
接口回调
- 需求:
A在执行循环,当循环到5的时候, 通知B。
事先先把一个对象传递给 A , 当A 执行到5的时候,通过这个对象,来调用B中的方法。 但是注意,不是直接传递B的实例,而是传递一个接口的实例过去。
建一个A类和B类
package com.wangshi;
public class A {
public void printA(){
//A在执行循环,当循环到5的时候, 通知B。
for (int i = 0; i <10; i++) {
System.out.println("循环到了"+i);
if(i==5){
System.out.println("这个时候已经循环到5了,现在去通知B");
B b = new B();
b.no5();
}
}
}
}
package com.wangshi;
public class B {
public void no5(){
System.out.println("当A 执行到5的时候,来调用B中的方法,现在调用");
}
}
测试结果
循环到了0-5
这个时候已经循环到5了,现在去通知B
当A 执行到5的时候,来调用B中的方法,现在调用
循环到了-6-9
package com.wangshi;
public class Test {
public static void main(String[] args) {
A a = new A();
a.printA();
}
}
AB类
package com.wangshi;
/**
* 1988年写的
* @author wanghaichaun
*
*/
public class A {
/**
* 这是以前的java基础使用的代码。
* 但是假设这个A这个类是早在上个世纪80年 就写好的A类, 这个方法 内部是不能直接new B()
* 1. 不能直接new B
*
* 2. 页不能传递B的实例进来。
*
* 所以在定义这个方法的时候,不管未来写的是B 类, 还是C类,还是D类, 人家为了通用。
* 所以定义了一种接口,只要让未来的那些类,实现这个接口。 然后这个方法的参数写 接口类型即可。
*/
/*public void print(){
for (int i = 0; i < 10; i++) {
System.out.println("循环到了--"+i);
if(i == 5){
System.out.println("循环到了5了,该通知B 了。");
B b = new B();
b.printFive();
}
}
}*/
public void print(PrintListener listener){
for (int i = 0; i < 10; i++) {
System.out.println("我在1988年就开始打印这个语句了。。循环到了--"+i);
if(i == 5){
System.out.println("循环到了5了,该通知 调用者 了。");
listener.print();
/*B b = new B();
b.printFive();*/
}
}
}
}
package com.wangshi;
/**2018
* @author wanghaichaun
*
*/
public class B implements PrintListener{
/*public void no5(){
System.out.println("当A 执行到5的时候,来调用B中的方法,现在调用");
}*/
@Override
public void print() {
System.out.println("2018年。。。A已经循环到了5, 所以B的这个方法将被调用");
}
}
创建PrintListener接口
package com.wangshi;
/**
* 1988年写
* 打印监听器
* @author xiaomi
*
*/
public interface PrintListener {
/**
* 一旦出现了某一种事件, 达到了某一个状态,就调用这个方法。
*/
void print();
}
实现:
public static void main(String[] args) {
A a = new A();
/*a.printA();*/
//这是多态的体现,
/*
* 这个方法咋i1988年就定义了要收 printlistener 这个接口的类型。
* 在2018年的时候有一个类 B 实现了这个接口printlistener ,
* 所以现在可以传递B进来
*/
a.print(new B());
}
###Web监听器
总共有8个, 划分成三种类型
-
定义一个类,实现接口
-
注册 | 配置监听器
监听三个作用域创建和销毁
request ---httpServletRequest
session ---httpSession
aapplication --- ServletContext
-
ServletContextListener
servletcontext创建:启动服务器的时候
servletContext销毁:关闭服务器or 从服务器移除项目 -
ServletRequestListener
request创建:访问服务器上的任意资源都会有请求出现。
访问 html: 会
访问 jsp: 会
访问 servlet : 会request销毁:服务器已经对这次请求作出了响应。
package com.wangshi;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
/**
* @author wanghaichuan
*Listener 监听器的三个作用域 的创建和销毁
* Application------->ServletContext -------->ServletContextListener
* request------------>httpServletRequest------>servletRequestListener ①
* Session------------>httpSession-------------->httpSessionListener
*/
public class MyServletRequestListener implements ServletRequestListener{
//销毁的时候调用 服务器已经对这次请求作出了响应。
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("ServletRequestListener 初始化了........");
}
//初始化的时候调用 访问服务器上的任意资源都会有请求出现。
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("ServletRequestListener 销毁了........");
}
}
//web.xml
<listener>
<listener-class>com.wangshi.MyServletRequestListener</listener-class>
</listener>
- HttpSessionListener
session的创建:只要调用getSession
html: 不会
jsp: 会 getSession();
servlet: 会
session的销毁:
超时 30分钟
非正常关闭 销毁
正常关闭服务器(序列化)
public class MySessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("创建session了");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("销毁session了");
}
}
作用:
- ServletContextListener
利用它来,在servletcontext创建的时候,
1. 完成自己想要的初始化工作
2. 执行自定义任务调度。 执行某一个任务。 Timer - HttpSessionListener
统计在线人数.
监听三个作用域属性状态变更
可以监听在作用域中值 添加 | 替换 | 移除的动作。
-
servletContext — ServletContextAttributeListener
-
request — ServletRequestAttributeListener
-
session — HttpSessionAttributeListener
监听httpSession里面存值的状态变更
这一类监听器不用注册。
- HttpSessionBindingListener
监听对象与session 绑定和解除绑定 的动作
- 让javaBean 实现该接口即可
@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("对象被绑定进来了");
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("对象被解除绑定");
}
- HttpSessionActivationListener
用于监听现在session的值 是 钝化 (序列化)还是活化 (反序列化)的动作
- 钝化 (序列化)
把内存中的数据 存储到硬盘上
- 活化 (反序列化)
把硬盘中的数据读取到内存中。
- session的钝化活化的用意何在
session中的值可能会很多, 并且我们有很长一段时间不使用这个内存中的值, 那么可以考虑把session的值可以存储到硬盘上【钝化】,等下一次在使用的时候,在从硬盘上提取出来。 【活化】
- 如何让session的在一定时间内钝化.
做配置即可 3种
-
在tomcat里面 conf/context.xml 里面配置对所有的运行在这个服务器的项目生效
-
在conf/Catalina/localhost/context.xml 配置对 localhost生效。 localhost:8080
-
在自己的web工程项目中的 META-INF/context.xml,只对当前的工程生效。
maxIdleSwap : 1分钟不用就钝化
directory : 钝化后的那个文件存放的目录位置。
D:\tomcat\apache-tomcat-7.0.52\work\Catalina\localhost\ListenerDemo\wangshi
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="wangshi"/>
</Manager>
</Context>
Filter
过滤器 , 其实就是对客户端发出来的请求进行过滤。 浏览器发出, 然后服务器派servlet处理。 在中间就可以过滤, 其实过滤器起到的是拦截的作用。
- 作用
- 对一些敏感词汇进行过滤
- 统一设置编码
- 自动登录
…
如何使用Filter
- 定义一个类, 实现Filter
package com.wangshi;
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 MyFilterDemo implements Filter {
/**销毁
* @see Filter#destroy()
*/
public void destroy() {
System.out.println("销毁了");
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("来到过滤器了。。。。");
chain.doFilter(request, response);
}
/**初始化
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("Filter 初始化了");
}
}
- 注册过滤器
在web.xml里面注册,注册的手法与servlet基本一样。
<filter>
<display-name>MyFilterDemo</display-name>
<filter-name>MyFilterDemo</filter-name>
<filter-class>com.wangshi.MyFilterDemo</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilterDemo</filter-name>
<url-pattern>/MyFilterDemo</url-pattern>
</filter-mapping>
<filter>
Filter的生命周期
-
创建
在服务器启动的时候就创建。 -
销毁
服务器停止的时候。
Filter执行顺序
-
客户端发出请求,先经过过滤器, 如果过滤器放行,那么才能到servlet
-
如果有多个过滤器, 那么他们会按照注册的映射顺序 来 排队。 只要有一个过滤器, 不放行,那么后面排队的过滤器以及咱们的servlet都不会收到请求。
Filter细节:
-
init方法的参数 FilterConfig , 可以用于获取filter在注册的名字 以及初始化参数。 其实这里的设计的初衷与ServletConfig是一样的。
-
如果想放行,那么在doFilter 方法里面操作,使用参数 chain
chain.doFilter(request, response); 放行, 让请求到达下一个目标。
-
<url-pattern>/*</url-pattern>
写法格式与servlet一样。-
全路径匹配 以 / 开始
/LoginServlet -
以目录匹配 以 / 开始 以 * 结束
/demo01/* -
以后缀名匹配 以 * 开始 以后缀名结束
*.jsp *.html *.do
-
-
针对 dispatcher 设置
REQUEST : 只要是请求过来,都拦截,默认就是REQUEST
FORWARD : 只要是转发都拦截。
ERROR : 页面出错发生跳转
INCLUDE : 包含页面的时候就拦截。
总结
Listener
8个 三种类型
针对三个作用域的创建和销毁
针对三个作用域的值改变 【添加 | 替换 | 移除】
针对session中的值 【钝化 活化】 , 【绑定 解绑】
钝化 ( 序列化 )
内存中的对象存储到硬盘
超时失效。 session销毁了。
非正常关闭服务器, 钝化 。 正常关闭服务器 销毁
设置了session,多久时间。 context.xml
活化 (反序列化)
从硬盘里面读取到内存
ServletContextListner : 应用被部署的时候, 服务器加载这个项目的时候,做一些初始化工作, 任务调度。
HttpSessionListener : 统计在线人数
HttpSessionActivationListener : 钝化活化处理
Filter
使用频率更高,eg:自动登录
- 如果要写一个过滤器。
- 定义一个类,实现接口 Filter
- 注册 . web.xml . 与servlet相似。
-
过滤器放行。
chain.doFilter(request, response); -
过滤器生命周期
创建: 服务器加载这个项目的时候创建实例
销毁: 关闭服务器或者从服务器中移除项目的时候。