监听器/过滤器

Servlet技术规范 描述三种技术 : Servlet(服务器小程序) 、Filter(过滤器) 、Listener(监听器)


Filter运行在服务器端,对服务器端web资源的访问 进行拦截,起到过滤的作用 


Servlet API中 定义接口 Filter,用户只需要编写程序实现Filter接口,完成过滤器编写 


Filter快速入门
1、编写类 实现 Filter接口
2、在服务器端注册 Filter (配置拦截哪个web资源) ----- web.xml 
  <!-- 注册过滤器 -->
  <filter>
  <filter-name>Filter1</filter-name>
  <filter-class>cn.itcast.filter.Filter1</filter-class>
  </filter>
  <!-- 配置过滤器去拦截哪个资源 -->
  <filter-mapping>
  <filter-name>Filter1</filter-name>
  <url-pattern>/hello.jsp</url-pattern>
  </filter-mapping>


3、客户端访问被拦截目标资源之前,服务器调用Filter的doFilter方法 ,执行过滤
4、Filter的doFilter方法中传入 FilterChain, 如果调用FilterChain的doFilter 就会执行目标资源,否则目标资源不会执行 
chain.doFilter(request, response);


FilterChain
在客户端访问服务器web资源时,服务器端为一个web资源,配置多个过滤器拦截 ,这多个过滤器,就会组成过滤器链 FilterChain, 调用FilterChain的doFilter 表示要执行过滤器链下一个资源,如果当前过滤器已经是链上最后一个过滤器,就会执行目标资源 


* web服务器根据Filter在web.xml文件中的注册顺序<mapping>,决定先调用哪个Filter


Filter生命周期 init(FilterConfig) doFilter(request,response,filterChain) destroy() 
1、Filter对象在tomcat服务器启动时 创建,调用init方法  (只会创建一个对象,init方法执行一次)
2、doFilter 每次拦截目标资源时,执行
3、destroy 服务器关闭时执行 


FilterConfig 作用和 ServletConfig 类似,用来在Filter初始化阶段,将参数传递给过滤器
1、通过  String getInitParameter(String name)  获得过滤器初始化参数 
2、通过 ServletContext getServletContext() 获得ServletContext对象 
* FilterConfig 提供参数,是Filter类私有参数,Filter2的初始化参数,不能在Filter1 中进行获取 
* 配置全局参数,<context-param> 进行配置,通过ServletContext 获得 


<filter-mapping> 过滤器拦截配置
1、如果连接目标资源是一个Servlet,可以选择url和servlet名称两种配置方式 
<!-- 拦截/hello是Servlet 路径 -->
<url-pattern>/hello</url-pattern>
<!-- 拦截Servlet 还可以通过Servlet 名称进行拦截 -->
<servlet-name>HelloServlet</servlet-name>
2、url-pattern 和 Servlet中路径写法一样,有三种 : 完全匹配、目录匹配、扩展名匹配
3、<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式
容器调用服务器端资源 有四种方式 
REQUEST、FORWARD、INCLUDE、ERROR


=========================================================================================================================================
Filter应用 


应用一:统一全站字符编码过滤器 
案例:编写jsp 输入用户名,在Servlet中获取用户名,将用户名输出到浏览器上 


处理请求post乱码代码
request.setCharacterEncoding("utf-8");
设置响应编码集代码
response.setContentType("text/html;charset=utf-8");


经常会使用,而过滤器可以在目标资源之前执行,将很多程序中处理乱码公共代码,提取到过滤器中 ,以后程序中不需要处理编码问题了 


应用二:禁止浏览器缓存动态页面的过滤器
因为动态页面数据,是由程序生成的,所以如果有缓存,就会发生,客户端查看数据不是最新数据情况 ,对于动态程序生成页面,设置浏览器端禁止缓存页面内容 


response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");


将禁用缓存代码,提起到过滤器中,通过url配置,禁用所有JSP页面的缓存 


应用三:控制浏览器缓存静态web资源
Tomcat缓存策略 


对于服务器端经常不变化文件,设置客户端缓存时间,在客户端资源缓存时间到期之前,就不会去访问服务器获取该资源 -------- 比tomcat内置缓存策略更优手段 
* 减少服务器请求次数,提升性能 


设置静态资源缓存时间,需要设置 Expires 过期时间 ,在客户端资源没有过期之前,不会产生对该资源的请求的 
* 设置Expires 通常使用 response.setDateHeader 进行设置 设置毫秒值 


===============================================================================================================================================
应用四:自动登陆过滤器
在访问一个站点,登陆时勾选自动登陆(三个月内不用登陆),操作系统后,关闭浏览器;过几天再次访问该站点时,直接进行登陆后状态 


在数据库中创建 user表


create table user (
   id int primary key auto_increment,
   username varchar(20),
   password varchar(40),
   role varchar(10)
);


insert into user values(null,'admin','123','admin');
insert into user values(null,'aaa','123','user');
insert into user values(null,'bbb','123','user');


自动登陆 :未登录、存在自动登陆信息、自动登陆信息正确 


在用户完成登陆后,勾选自动登陆复选框,服务器端将用户名和密码 以Cookie形式,保存在客户端 。当用户下次访问该站点,AutoLoginFilter 过滤器从Cookie中获取 自动登陆信息 
1、判断用户是否已经登陆,如果已经登陆,没有自动登陆的必要
2、判断Cookie中是否含有自动登陆信息 ,如果没有,无法完成自动登陆
3、使用cookie用户名和密码 完成自动登陆 


如果将用户密码保存在cookie文件中,非常不安全的 ,通常情况下密码需要加密后才能保存到客户端 
* 使用md5算法对密码进行加密 
* md5 加密算法是一个单向加密算法 ,支持明文---密文 不支持密文解密 


MySQL数据库中提供md5 函数,可以完成md5 加密
mysql> select md5('123'); 
+----------------------------------+
| md5('123')                       |
+----------------------------------+
| 202cb962ac59075b964b07152d234b70 |
+----------------------------------+
解密后结果是32位数字 16进制表示 


Java中提供类 MessageDigest 完成MD5加密


------------------------------------------------------------------
将数据表中所有密码 变为密文 update user set password = md5(password) ;
在Demo4Servlet 登陆逻辑中,对密码进行md5 加密 
在AutoLoginFilter 因为从Cookie中获得就是加密后密码,所以登陆时无需再次加密 




------------------------------------------------------------------
MD5 在2004 年被王小云破解,md5算法是多对一加密算法,出现两个加密后相同密文的明文很难发现 ,王小云并没有研究出md5 解密算法,研究出一种提高碰撞概率的算法 


-------------------------------------------------------------------
应用五:过滤器实现URL级别权限认证
系统中存在很多资源,将需要进行权限控制的资源,放入特殊路径中,编写过滤器管理访问特殊路径的请求,如果没有相应身份和权限,控制无法访问 


认证:who are you ? 用户身份的识别 ------------ 登陆功能
权限:以认证为基础 what can you do ? 您能做什么? 必须先登陆,才有身份,有了身份,才能确定可以执行哪些操作 


=====================================================================================================================================================
Filter高级应用


Decorator模式 
1、包装类需要和被包装对象 实现相同接口,或者继承相同父类
2、包装类需要持有 被包装对象的引用 
在包装类中定义成员变量,通过包装类构造方法,传入被包装对象 
3、在包装类中,可以控制原来那些方法需要加强
不需要加强 ,调用被包装对象的方法
需要加强,编写增强代码逻辑 


ServletRequestWrapper 和 HttpServletRequestWrapper 提供对request对象进行包装的方法,但是默认情况下每个方法都是调用原来request对象的方法,也就是说包装类并没有对request进行增强 


在这两个包装类基础上,继承HttpServletRequestWrapper ,覆盖需要增强的方法即可 


应用六:完全解决get和post乱码的过滤器 
在Filter中,对request对象进行包装,增强获得参数的方法 
getParameter 
getParameterValues
getParameterMap 




ServletResponseWrapper 和 HttpServletResponseWrapper 提供了对response 对象包装,继承 HttpServletResponseWrapper ,覆盖需要增强response的方法 


应用七:增强Response对象,对响应数据进行压缩
复习:Tomcat服务器内,提供对响应压缩 配置实现 
在conf/server.xml 中 
<Connector port="80" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443"/> 添加 compressableMimeType 和 compression
没有压缩 :  00:00:00.000 0.063 7553 GET 200 text/html http://localhost/


<Connector port="80" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" compressableMimeType="text/html,text/xml,text/plain" compression="on"/>


压缩后 :  00:00:00.000 0.171 2715 GET 200 text/html http://localhost/ 
Content-Encoding: gzip
Content-Length : 2715


实际开发中,很多情况下,没有权限配置server.xml  ,无法通过tomcat配置开启gzip 压缩


编写过滤器对响应数据进行gzip压缩 


flush 方法
只有没有缓冲区字节流,FileOutputStream 不需要flush 

而字节数组ByteArrayOutputStream、字节包装流、字符流 需要flush ----- 这些流在调用close方法时都会自动flush 

--------------------------------------------------------------------------------------------------------------------------------------------------------


监听器:监听器就是一个java程序,功能是监听另一个java对象变化(方法调用、属性变更)


监听器监听过程:事件源、事件对象、监听器对象 、操作事件源
1、存在被监听对象(事件源)
2、存在监听器对象 
3、在事件源中注册监听器 
4、操作事件源,使事件源发生改变 ,产生事件对象 
* 事件对象 就是 事件源的改变 
5、事件对象会被传递给监听器,触发监听器相应行为


监听器技术主要应用于图形界面编程 ---------- swing中监听器的使用


自定义监听器  ---- 监听人的行为(监听器案例)
1、创建事件源对象 Person
2、创建监听器对象 (通常定义为接口) PersonListener 
3、注册监听器
4、触发事件源改变 --- 产生事件对象


思考:事件对象能用来做什么 ??
事件对象传递事件源的数据给监听器 ,通过事件对象获得事件源对象 
* 监听器可以监听到事件源的数据变化 


============================================================================================
监听器:监听器就是一个java程序,功能是监听另一个java对象变化(方法调用、属性变更)


监听器监听过程:事件源、事件对象、监听器对象 、操作事件源
1、存在被监听对象(事件源)
2、存在监听器对象 
3、在事件源中注册监听器 
4、操作事件源,使事件源发生改变 ,产生事件对象 
* 事件对象 就是 事件源的改变 
5、事件对象会被传递给监听器,触发监听器相应行为


监听器技术主要应用于图形界面编程 ---------- swing中监听器的使用


自定义监听器  ---- 监听人的行为(监听器案例)
1、创建事件源对象 Person
2、创建监听器对象 (通常定义为接口) PersonListener 
3、注册监听器
4、触发事件源改变 --- 产生事件对象


思考:事件对象能用来做什么 ??
事件对象传递事件源的数据给监听器 ,通过事件对象获得事件源对象 
* 监听器可以监听到事件源的数据变化 


============================================================================================
今天的学习目标:Servlet提供8个监听器对象 
Servlet提供8个监听器,监听事件源主要是三个对象 : ServletRequest, HttpSession, ServletContext ------Servlet的三种数据范围对象 


Servlet的8个监听器,分为三类:
第一类:监听三个数据范围对象(request、session、ServletContext)的创建和销毁监听器 
第二类:监听三个数据范围对象中属性变更(增加、替换、删除)的监听器
第三类:监听HttpSession中对象状态改变(被绑定、解除绑定、钝化、活化)的监听器


一、三个域对象创建和销毁监听器
1、ServletContextListener 监听 ServletContext 对象的创建和销毁事件  
void contextInitialized(ServletContextEvent sce) ---- 监听Context对象创建 
void contextDestroyed(ServletContextEvent sce)  ----- 监听Context对象的销毁


ServletContext 全局唯一对象,每个工程创建唯一Context对象(配置全局初始化参数、保存全局共享数据、读取web资源文件) 
在服务器启动时创建ServletContext对象,在服务器关闭时销毁ServletContext对象 


编写监听器步骤
1) 编写类 ,实现特定监听器接口 
2) Servlet监听器,不是注册在事件源上,而是注册在web.xml 中,由容器tomcat完成监听器注册 
  <!-- 注册监听器 , tomcat将监听器注册给事件源, 事件源操作后,会自动监听器执行 -->
  <!-- 和Servlet Filter不同,不需要配置url -->
  <listener>
  <listener-class>cn.itcast.web.listener.MyServletContextListener</listener-class>
  </listener>


应用:
1) 保存全局范围对象,因为监听ServletContext对象,监听器都可以通过事件对象获得事件源  
// 获得被监听事件源对象
ServletContext context = sce.getServletContext();
2) 读取框架配置文件 例如: spring框架 org.springframework.web.context.ContextLoaderListener 
3) 在ServletContextListener 定义一些定时器程序 (任务调度程序)


最简单java中任务调度 ----- 定时器Timer 和 TimerTask的使用
Timer启动定时器任务
void schedule(TimerTask task, Date firstTime, long period)  ------- 指定启动任务第一次时间,通过period参数指定任务重复执行
void schedule(TimerTask task, long delay, long period) ----- 指定任务距离当前时间delay 多久开始启动,通过period指定任务重复执行 


终止定时器任务执行 timer.cancel(); 


2、HttpSessionListener  监听HttpSession对象的创建和销毁
void sessionCreated(HttpSessionEvent se)  ----- 监听Session对象创建
void sessionDestroyed(HttpSessionEvent se)  ---- 监听Session对象销毁 


Session对象何时创建 : request.getSession(); 第一次执行时 创建Session对象 
* 访问JSP时,因为其内置对象session,所以一定会创建Session对象的 


Session对象何时销毁 : 1) 不正常关闭服务器 2) Session对象过期 3) invalidate方法调用
* 正常关闭服务器时,Session的数据保存tomcat/work目录下  --- 产生 SESSIONS.ser 
* session的过期时间在web.xml 进行配置 
  <session-config>
  <!-- 单位是分钟,连续30分钟没有使用该Session对象,就会销毁对象 -->
  <session-timeout>30</session-timeout>
  </session-config>


3、ServletRequestListener 监听Request对象的创建和销毁 
void requestDestroyed(ServletRequestEvent sre)   ----- 监听request对象销毁的
void requestInitialized(ServletRequestEvent sre)  ---- 监听request对象创建的


每次客户端发起一次新的请求 产生request对象,当response响应结束后,request对象进行销毁 


forward不会产生新的request对象,sendRedirect产生新的request对象 


监听器案例:
案例一: 统计当前在线人数 
分析:统计Session 的个数 ,存在一个Session,意味着一个浏览器在访问 


案例二: 自定义session定时扫描器(销毁session对象)
编写定时器程序,定时去扫描系统中所有Session对象,发现如果一个Session 1分钟没有使用了,就销毁该Session对象 


=============================================================================================================================
二、ServletRequest、HttpSession、ServletContext 三个数据范围中 数据变更监听器 
ServletContextAttributeListener, HttpSessionAttributeListener ServletRequestAttributeListener


这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件
1、attributeAdded  属性添加方法 
public void attributeAdded(ServletContextAttributeEvent scae) 
public void attributeAdded (HttpSessionBindingEvent  hsbe) 
public void attributeAdded(ServletRequestAttributeEvent srae)


2、attributeRemoved  属性移除方法
public void attributeRemoved(ServletContextAttributeEvent scae) 
public void attributeRemoved (HttpSessionBindingEvent  hsbe) 
public void attributeRemoved (ServletRequestAttributeEvent srae)


3、attributeReplaced  属性替换方法
public void attributeReplaced(ServletContextAttributeEvent scae) 
public void attributeReplaced (HttpSessionBindingEvent  hsbe) 
public void attributeReplaced (ServletRequestAttributeEvent srae)


何时调用attributeAdded 、attributeRemoved  、attributeReplaced  ? 
以HttpSessionAttributeListener为例 
        // 向session中添加了一个属性
session.setAttribute("name","张三"); // 因为name属性还不存在 --- attributeAdded


// 向Session保存属性name的值李四,因为name属性已经存在,替换效果
session.setAttribute("name","李四"); // 因为name属性以及存在 --- attributeReplaced

// 移除session的属性name
session.removeAttribute("name"); // 移除name属性 ---- attributeRemoved


****** 如果执行session.invalidate(); 销毁了Session 导致Session中所有属性被移除 


===========================================================================================================================
三、Session中对象状态改变 监听器
Session中对象共有四种状态
1、绑定 ----- 对象被添加到Session中
2、解除绑定 ----- 对象从Session中移除 
3、钝化 ----- Session中数据被序列化到硬盘上 
4、活化 ----- Session序列化数据 从硬盘被加载回内存 


使JavaBean 了解到自己在Session中状态的变化 
HttpSessionBindingListener 感知到绑定以及解除绑定
HttpSessionActivationListener 感知钝化和活化 状态改变 


不需要 web.xml 文件中进行注册 (这两类监听器,不是由容器进行管理的,由HttpSession对象管理 )


HttpSessionBindingListener
void valueBound(HttpSessionBindingEvent event)  绑定
void valueUnbound(HttpSessionBindingEvent event)  解除绑定 


编写javabean实现 HttpSessionBindingListener接口,该javabean对象感知到自己被绑定到Session或者从Session解除绑定 
valueBound , 当对象被加入session 就会执行
valueUnbound, 当对象从Session 移除时 就会执行 


HttpSessionActivationListener 监听对象被钝化和活化 
void sessionDidActivate(HttpSessionEvent se)  活化 
void sessionWillPassivate(HttpSessionEvent se)  钝化 (java对象被序列化到硬盘上 )


如果tomcat正常关闭,Session中对象会被序列化到硬盘上 ---- java对象如果能被序列化必须实现Serializable接口 
异常 :IOException while loading persisted sessions: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: cn.itcast.bean.Bean2
原因 :恢复Session.ser文件时,因为需要对象无法从文件中加载,发生异常 (删除Session.ser就可以了 )
* 保存到Session中对象,应该被序列化 


在Session中数据对象,保存了一段时间后没有使用,不想删除对象中数据,(在不关闭服务器情况下)可以让对象数据进行钝化 ---- 序列化到硬盘上 
下次再访问数据时,从钝化的文件中读取序列化数据 ----- 对数据进行活化 
* 由tomcat完成钝化和活化,配置<Context> 标签 
配置Context标签有三个常用位置
1) tomcat/conf/context.xml 所有虚拟主机、所有web应用都可以使用配置
2) tomcat/conf/Catalina/localhost/context.xml 当前虚拟主机 所有web应用都可以使用配置
3) 当前工程/META-INF/context.xml  只对当前工程有效 


配置钝化目录在tomcat/work 下 ---- 和Session默认保存位置一样 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值