过滤器 | 监听器 | 拦截器 | |
---|---|---|---|
关注的点 | web请求 | 系统级别的参数 | Action |
如何实现 | 函数回调 | 事件 | java反射机制(动态代理) |
应用场景 | 设置字符编码,URL级别的权限控制访问 | 统计网站在线人数 | 拦截未登录用户 |
是否依赖servlet容器 | 是 | 否 |
过滤器
主要针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验
它依赖于servlet容器。在实现上,基于函数回调,它可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的,是用来做一些过滤操作,获取我们想要获取的数据,比如:在Javaweb中,对传入的request、response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者Controller进行业务逻辑操作。通常用的场景是:在过滤器中修改字符编码(CharacterEncodingFilter)、在过滤器中修改HttpServletRequest的一些参数(XSSFilter(自定义过滤器)),如:过滤低俗文字、危险字符等
自定义过滤器实现javax.servlet包下的Filter接口,并重写doFilter方法
package com.sansux.Filter_Listener_interceptor;
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 java.io.IOException;
/**
* Created by zhouhaihua on 2018/9/23
*/
public class AuthFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("authFilter 开始工作··");
chain.doFilter(request,response); // 继续执行后续操作
}
@Override
public void destroy() {
}
}
web.xml中的配置
<filter>
<filter-name>authFilter</filter-name>
<filter-class>com.sansux.Filter_Listener_intecerptor.AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>authFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
拦截器
拦截器的配置一般在SpringMVC的配置文件中,使用Interceptors标签,
拦截器是基于java反射机制的,属于面向切面编程的一种运用,可以使用spring的依赖注入进行业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller进行拦截,对其他一些静态资源则无法进行拦截处理
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
1.通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。
2.通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。
以实现HandlerInterceptor为例
package com.sansux.Filter_Listener_interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by zhouhaihua on 2018/9/23
*/
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
上述代码中,自定义拦截器实现了HandlerInterceptor接口,并实现了接口中的三个方法:
preHandle() 方法:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行;
当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。
postHandle()方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。
afterCompletion()方法:该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
mvc.xml中的配置
<mvc:interceptors>
<!--<bean class="com.sansux.Filter_Listener_interceptor.CustomeInterceptor" />-->
<!--拦截器1-->
<mvc:interceptor>
<!--配置拦截器的作用路径-->
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path=""/>
<!--定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截-->
<bean class="com.sansux.Filter_Listener_interceptor.Intercptor1"/>
</mvc:interceptor>
<!--拦截器2-->
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean class="com.sansux.Filter_Listener_interceptor.Interceptor2"/>
</mvc:interceptor>
二者的区别
- 使用范围不同
Filter是Servlet规范规定的,只能用于web程序中,而拦截器可以用于web程序、Application和swing - 规范不同
Filter在servlet中定义,是servlet容器支持的,而拦截器是spring框架支持的 - 使用的资源不同(拦截器可以访问action上下文、值栈里的对象,而过滤器不能。)
拦截器也是spring的一个组件,归spring容器管理,配置在spring文件中,因此能使用spring中的任何资源、对象。例如service、对象、数据源、事务管理等,通过Ioc注册到拦截器 - 深度不同
Filter只在Servlet前后起作用,而拦截器能够深入到方法前后、异常抛出前后,因此拦截器具有更大的弹性,在spring结构的程序中,优先使用拦截器 - 拦截器基于jdk反射(动态代理),过滤器是基于函数回调
- 拦截器只对action起作用,过滤器可以对几乎所有请求起作用
监听器
javaweb共有八类监听器,分为三类
-
用来监听三大作用域的创建和销毁的监听器
ServletContextListener(接口) 用来监听ServletContext对象创建和销毁的监听器
创建:服务器启动,web应用加载后立即创建代表当前web应用的ServletContext对象
销毁:服务器关闭或web应用被移除出容器时,随着web应用的销毁而销毁
HttpSessionListener(接口) 用来监听HttpSession对象创建和销毁的监听器
创建:第一次调用request.getSession方法时创建代表当前会话的session对象
销毁:超过30分钟没人用销毁/调用invalidate方法自杀/服务器非正常关闭时随着web应用的销毁而销毁,如果服务器是正常关闭会被钝化起来.当服务器正常关闭时,还存活着的session会随着服务器的关闭被以文件的形式存储在tomcat的work目录下,这个过程叫做session的钝化
当服务器再次正常开启时,服务器会找到之前的SESSIONS.ser文件从中恢复之前保存起来的session对象这个过程叫做session的活化
想要随着Session被钝化活化的对象它的类必须实现Serializable接口ServletRequestListener(接口) 用来监听ServletRequest对象创建和销毁的监听
创建:请求开始创建代表请求的request对象
销毁:请求结束时代表请求的request对象销毁 -
用来监听三大作用域中属性变化的监听器
ServletContextAttributeListener(接口)
HttpSessionAttributeListener (接口)
ServletRequestAttributeListener(接口) -
使javabean自己感知自己在Session中状态变化的监听器,这两个监听器很特殊,不需要自己去写类实现也不需要在web.xml中注册,只要使javabean实现这个接口就能起作用
HttpSessionBindingListener(接口)
javabean被绑定到session中
sessionDidActive(HttpSessionBindingEvent event)
javabean被移除绑定从session中
valueUnbound(HttpSessionBindingEvent event)方法HttpSessionActivationListener (接口)
javabean随着session被钝化
sessionWillPassivate(HttpSessionBindingEvent event)
javabean随着session被活化
sessionDidActive(HttpSessionBindingEvent event)
HttpSessionListeners
public interface HttpSessionListener extends EventListener {
public void sessionCreated ( HttpSessionEvent se );
public void sessionDestroyed ( HttpSessionEvent se )
}
自定义监听器实现HttpSessionListener,统计网站在线人数
public class MyHttpSessionListener implements HttpSessionListener{
public static int peopleOnLine = 0;
@Override
public void sessionCreated(HttpSessionEvent arg0) {
System.out.println("myHttpSessionListener.sessionCreated():"+arg0);
peopleOnLine++;
arg0.getSession().setAttribute("peopleOnLine",peopleOnLine);
}
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("myHttpSessionListener.sessionDestroyed():"+arg0);
peopleOnLine--;
arg0.getSession().setAttribute("peopleOnLine",peopleOnLine);
}
}
web.xml中的配置
<listener>
<listener-class>com.sansux.listener.MyHttpSessionListener</listener-class>
</listener>
在前端页面获取在线人数
<%=session.getAttribute("peopleOnLine")%>