过滤器和监听器总结
一、过滤器 Filter
1. 什么是过滤器?
过滤期正如我们生活中用来过滤东西的东西,泡茶喝,用纱网过滤茶叶一样。再web中,当我们浏览器访问服务器时候,浏览器所发送的请求会先经过过滤器被拦截下来,让过滤器来执行某些操作。在实际开发中,过滤器的常用用途有登录验证、统一编码处理、过滤敏感字符等等
2. 入门
要创建一个过滤器,只需要创建一个Java类,然后让过滤器实现Filter接口,然后重写里面的三个方法:init、doFilter、destroy即可,最后再配置一下拦截路径即可。
首先,对于inti、destroy方法,他和servlet是一样的,在服务器加载和销毁的时候会执行一次,通常inti用来加载资源,而服务器在正常关闭后,Filter对象被销毁,只执行一次destroy方法,用于释放资源
对于doFilter,他是在每次请求拦截资源时候,都会执行,所以他是执行多次的。要注意,该方法有三个参数,前两个我们都很熟悉了,对于第三个参数FilterChain,他是一个接口,在该接口中又定义了doFilter方法。这是咋回事呢?可以这样理解:过滤器不单只有一个,在Java中就使用了链式结构。把所有的过滤器都放在FilterChain里边,如果符合条件,就执行下一个过滤器(如果没有过滤器了,就执行目标资源)。
3. 执行流程
- 先执行过滤器
- 执行放行后的资源
- 最后再返回回来执行放行代码下面的其他代码
4. 配置拦截路径
4.1 注解配置方法
若要使用注解方法配置拦截路径,需要在Filter前面加上@WebFilter()
括号里面的就是拦截路径,如果只写拦截路径,可以不写参数名,因为默认就是value/urlPattern
,如果还要设置其他参数的话,那么就要加上参数名了。如果想要部分的Web资源进行过滤器过滤则需要指定Web资源的名称即可。
若要指定过滤器拦截的资源被Servlet容器调用的方式,那么可以设置dispatcherTypes
,有:DispatcherType.REQUEST(默认)、DispatcherType.ERROR、DispatcherType.FROWARD、DispatcherType.INCLUDE、DispatcherType.ASYNC五种方式,分别对应如下:
- REQUEST:默认值。浏览器直接请求资源
- FORWARD:转发访问资源
- INCLUDE:包含访问资源
- ERROR:错误跳转资源
- ASYNC:异步访问资源
4.2web.xml配置方法
在web.xml中,添加如下代码:filter用于注册过滤器,如果没有配置的话,即使实现类Filter接口也没有用
<filter>
<filter-name>设置一个filter名</filter-name>
<filter-class>要配置的Filter的全类名</filter-class>
<!-- 用于为过滤器指定的初始参数,在init中可以通过filterConfig来获取 -->
<init-param>
<param-name>word_file</param-name>
<param-value>/WEB-INF/word.txt</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>对应上面的filter名</filter-name>
<url-pattern>设置拦截路径</url-pattern>
<dispatcher>?指定 Filter 对资源的多种调用方式进行拦截(默认REQUEST)</dispatcher>
<servlet-name>过滤指定的servlet的资源名称</servlet-name>
</filter-mapping>
5. 多个过滤器(过滤器链)的执行顺序
- 过滤器1
- 过滤器2
- 过滤器3
- 执行目标资源
- 过滤器3的剩下的代码
- 过滤器2的剩下的代码
- 过滤器1的剩下的代码
过滤器的先后执行顺序问题是怎样的?
- 如果使用的是web.xml配置的话,那么你的“filter-mapping`哪个写在前面就会先执行哪个过滤器,写在后面的就会后执行,和filter无关。
- 如果使用的是注解的配置方式的话,那么会比较过滤器的类名,值小的先执行,例如a小于b,所以a过滤器会先执行
6. 过滤器的简单应用
6.1 禁止浏览器缓存
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
// 只有HttpServletResponse才可以设置响应信息,所以我们一般都将他们转化为Http
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// 设置禁止缓存
response.setDateHeader("Expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
chain.doFilter(request, response);
}
设置之后响应头为:
6.2 实现自动登录
6.3 编码过滤器
- 可以通过实现HTTP ServletRequestWrapper类来增强request对象
6.4 敏感词汇过滤
- 可以使用动态代理实现敏感词汇过滤
6.5 压缩资源过滤器
6.6 HTML转义过滤器
6.7 缓存数据到内存中
二、监听器 Listener
什么是监听器?
监听器就是⼀个实现特定接⼝的普通java程序,这个程序专⻔⽤于监听另⼀个java对象的⽅法调
⽤或属性改变,当被监听对象发⽣上述事件后,监听器某个⽅法将⽴即被执⾏。
事件监听机制
-
事件源:事件发生的对象,即被监听的对象
-
事件对象:封装事件源和动作
-
事件监听器:将事件对象传入,由开发人员编写监听器对象处理事件对象
-
注册监听:在事件源上关联监听器对象
内置监听器
在Servlet规范中定义了多种类型的监听器,它们⽤于监听的事件源分别 ServletContext,HttpSession和ServletRequest 这三个域对象
Servlet监听器的注册不是在事件源上,而是由web容器负责,我们只需要在web.xml中配置好
监听对象的创建和销毁
HttpSessionListener、ServletContextListener、ServletRequestListener分别监听着Session、Context、Request对象的创建和销毁
- HttpSessionListener(可以⽤来收集在线者信息)
- ServletContextListener(可以获取web.xml⾥⾯的参数配置)
- ServletRequestListener
监听对象属性的变化
ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener 分别监听着Context、Session、Request对象属性的变化
着三个接口都定义了以以下三个方法来处理被监听对象中的属性的增加、删除、替换事件,同一个事件在三个接口中方法名完全相同,只是接受的参数类型不同:
- attributeAdded()
- attributeRemoved()
- attributeReplaced()
监听Session内的对象
除了上面的6中listener,还有两种listener监听Session的对象:HttpSessionBindingListerner和HttpSsessionActivation:
- HttpSessionBindingListener: JavaBean对象可以感知自己被绑定到Session中和从Session中的删除的事件( 和HttpSessionAttributeListener的作用是差不多的 )
- HttpSessionActivationListener: JavaBend对象可以感知自己被活化和钝化的事件( 当服务器关闭时, 会将Session的内容保存在硬盘上[钝化], 当服务器开启时, 会将Session的内容在硬盘上重新加载[活化] )
想要测试出Session的硬化和钝化,需要修改Tomcat的配置的。在META-INF下的context.xml⽂件中添加下⾯的代码:
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="linzeliang"/>
</Manager>
</Context>
监听器的应用
- 统计网站在线人数
- 监听Session是否被创建了
- 如果Session创建了, Context域对象的人数的值就+1
- 如果Session被移除了, 那么值就-1
- 自定义Session扫描器
- 监听Session和Context的创建
- 使用一个容器来装Session
- 定时扫描容器中的Session,如果长时间没用就remove
- 在线踢人
- 也是使用容器来装Session
- 列出所用用户
- 可以选择将列出用户(Session)踢掉, 即删除Session