监听器(listener),过滤器(filter),拦截器(interceptor)是在开发过程中应用广泛的工具,对三者的区别以及作用做一个总结。如果发现有问题,欢迎指正,转载请注明出处。
一.执行顺序:
在常用的ssm框架中,对于监听器,过滤器是配置在web.xml中,执行顺序为:context-param-->listener-->filter-->servlet.
拦截器是在Spring MVC中配置的,整体的一个servlet请求的执行过程:context-param-->listener-->filter-->servlet-->interceptor
1.1 详解
context-param:就是一些需要初始化的配置,放入context-param中,被监听器监听,然后加载;
监听器(listener):对项目起到监听的作用,能监听到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化;
servlet:就是对request和response进行处理的容器,它在filter之后执行。servlet其中的一部分就是controller层(标记为servlet_2),还包括渲染视图层(标记为servlet_3)和进入controller之前系统的一些处理部分(servlet_1),另外我们把servlet开始的时刻标记为servlet_0,servlet结束的时刻标记为servlet_4。
过滤器(filter):对请求起到过滤的作用,它在监听器之后,作用在servlet之前,对请求进行过滤;
拦截器(interceptor):就是对请求和返回进行拦截,它作用在servlet的内部,具体来说有三个地方:
1)servlet_1和servlet_2之间,即请求还没有到controller层
2)servlet_2和servlet_3之间,即请求走出controller层次,还没有到渲染时图层
3)servlet_3和servlet_4之间,即结束视图渲染,但是还没有到servlet的结束
1.2 三者之间的关系:
拦截器 | Introspector | aop的一种实现 | 依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。 在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用
只能对controller请求进行拦截,对直接访问静态资源的请求则没办法进行拦截处理 | org.springframework.web. servlet.HandlerInterceptor |
过滤器 | Filter | 特殊的Servlet | Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
在过滤器中修改字符编码; 在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等 | javax.servlet.Filter |
监听器 | Listener | 系统级 | 1)监听 Session、request、context 的创建于销毁,分别为 HttpSessionLister、ServletContextListener、ServletRequestListener 2)监听对象属性变化,分别为: HttpSessionAttributeLister、ServletContextAttributeListener、ServletRequestAttributeListener | avax.servlet.ServletContextListener |
1.3 使用原则
1):当需要监听到项目中的一些信息,并且不需要对流程做更改时,用监听器;
2):当需要过滤掉其中的部分信息,只留一部分时,就用过滤器;
3):当需要对其流程进行更改,做相关的记录时用拦截器。
二.应用
2.1 监听器
1):监听器Listene:实现了javax.servlet.ServletContextListener 接口的服务器端程序,随web应 用的启动而启 动,只 初始化一次,随web应用的停止而销毁。 在javax.servlet.ServletContextListener接口中定义了2种方法: void contextInitialized(ServletContextEvent sce) 监听器的初始化 void contextDestroyed(ServletContextEvent sce) 监听器销毁 2):主要作用是:初始化的内容添加工作、设置一些基本的内容、比如一些参数或固定的对象等等。
3):应用:例如监听器对数据库连接池DataSource的初始化
2.1.1 配置:
1): 在web.xml中加入以下配置项,自动装配(监听)ApplicationContext.xml的配置信息
<!-- 以下为配置项:配置之后在web应用中就可以通过ServletContext取得BasicDataSource对象-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2):也可以加入自定义监听器,在容器启动时设置一些基本的内容、比如一些参数或固定的对象
创建监听器工具类,实现javax.servlet.ServletContextListener接口,重写contextInitialized与contextDestroyed两个方法
package ssm.listener;
import java.text.MessageFormat;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
/**
* 执行初始化操作
* 当servlet容器初始化完成后便会调用此方法。
* 用处:比如创建数据库连接
*/
@Override
public void contextInitialized(ServletContextEvent arg0) {
// 获取ServletContext的实例。
ServletContext servletContext = arg0.getServletContext();
//初始化参数
servletContext.setAttribute("name", "张三");
Object attribute = servletContext.getAttribute("name");
System.out.println("attribute: "+attribute);
}
/**
* 执行初始化操作
* 当应用程序从服务器取消部署时被调用。
*/
@Override
public void contextDestroyed(ServletContextEvent arg0) {
/**
* eclipse或myeclipse来开启和关闭tomcat,控制台是不显示内容的,
* 在tomcat的安装目录下,使用开启或关闭tomcat命令,可以看到走了contextDestroyed方法。
*/
System.out.println("关闭服务");
}
}
在web.xml中将注册自定义监听器
<!-- 以下为配置项:配置之后在web应用中就可以通过ServletContext取得BasicDataSource对象-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 以下配置项:自定义监听器-->
<listener>
<listener-class>ssm.listener.MyServletContextListener</listener-class>
</listener>
2.2 过滤器
1):过滤器Filter:实现了javax.servlet.Filter 接口的服务器端程序,随web应 用的启动而启动,只 初始化一次, 随web应用的停止而销毁。 在javax.servlet.Filter接口中定义了3个方法: void init(FilterConfig filterConfig) 用于完成过滤器的初始化 void destroy() 用于过滤器销毁前,完成某些资源的回收 void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) 实现过滤功 能,该方法对每个请求增加额外的处理
2):主要作用是:过滤字符编码、做一些业务逻辑判断等。
3):应用:在web.xml文件配置好要过滤的客户端请求,它都会拦截到请求,此时可以对请求或响应(Request、 Response)统一设置编码,简化操作;同时还可以进行逻辑判断,如用户是否已经登录、有没有权限 访问该页面等等。
2.2.1 配置:
在web.xml中加入以下配置项
<!-- 解决post乱码问题的过滤器 -->
<!-- post乱码问题的过滤器,拦截post请求并编码为utf8 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<!-- 解决post乱码问题的过滤器 -->
<!--
1.由<filter>和 <filter-mapping>组成。<filter-mapping>需要写在后面。
2<filter-name> 是自己命名的。注意mapping中的<filter-name>需要和filter中的一样。且如果是多个过滤器,name不能重复。
3.<filter-class>是自己的类的路径精确到类名。
4.<url-pattern>过滤的url 类型,这里是* 意思是所有请求都需要经过这个过滤器。
5.如果是多个过滤器,它是按照 <filter-mapping>的顺序运行的。
-->
<filter>
<filter-name>filter</filter-name>
<filter-class>ssm.filter.myFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
创建过滤器工具类,实现javax.servlet.Filter 接口,重写init;destroy;doFilter三个方法
package ssm.filter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public class myFilter implements Filter{
private String encoding;
private FilterConfig Config;
/**
* 在Filter销毁前,某些资源的回收
*/
@Override
public void destroy() {
// TODO Auto-generated method stub
}
/**
* 实现过滤功能,该方法对每个请求增加额外的处理
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("实现过滤功能,该方法对每个请求增加额外的处理");
chain.doFilter(request, response); // 放行,转到下一个过滤器
}
/**
* Filter的初始化
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter的初始化");
}
}
2.3 拦截器
1):拦截器Interceptor:实现了org.springframework.web.servlet.HandlerInterceptor接口,拦截器是在面向切面 编程中应用的。 在 org.springframework.web.servlet.HandlerInterceptor接口中定义了3个方法: preHandle 在业务处理器处理请求之前被调用 afterCompletion 在业务处理器处理请求完成之后,生成视图之前执行 afterCompletion DispatcherServlet 完全处理完请求之后被调用,可用于清理资源
2):主要作用是:拦截请求。
3):应用:动态代理就是拦截器的简单实现
2.3.1 配置:
拦截器不是在web.xml配置,在springMVC在spring与springMVC整合的配置文件中配置。
在springmvc.xml中加入以下配置项
<!-- 配置拦截器,可以直接定义拦截所有请求,也可以自定义拦截路径 -->
<mvc:interceptors>
<!-- 直接定义拦截所有请求 com.ssm.interceptor.IdentityInterceptor 为自定义拦截器包路径
<bean class="com.ssm.interceptor.IdentityInterceptor"></bean>-->
<mvc:interceptor>
<!-- 拦截/user下的所有方法径-->
<mvc:mapping path="/**"/>
<!-- 可以选择不拦截登录和添加以及其他的方法,根据情况自己定-->
<mvc:exclude-mapping path="/user/login"/>
<mvc:exclude-mapping path="/user/add"/>
<bean class="ssm.interceptor.IdentityInterceptor"></bean>
</mvc:interceptor>
<!--
<mvc:interceptor>配置多个拦截器 </mvc:interceptor>
-->
</mvc:interceptors>
<!-- 配置拦截器,可以直接定义拦截所有请求,也可以自定义拦截路径 -->
创建过滤器工具类,实现org.springframework.web.servlet.HandlerInterceptor接口,重写三个方法
package ssm.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class IdentityInterceptor implements HandlerInterceptor{
// 在业务处理器处理请求之前被调用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("1111111111111");
return true;
}
// 在业务处理器处理请求完成之后,生成视图之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
//完全处理完请求之后被调用,可用于清理资源
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}