参考文章1
过滤器、监听器、拦截器
- 一、监听器
- 二、过滤器
- 1. POM.xml导包
- 2. web.xml配置
- 3. Filter过滤器编程
- 三、拦截器
- 1. 定义拦截器
- 2. 配置加载拦截器
- 3. 新建页面的存放地点
- 四、过滤器、监听器、拦截器
- 1. 三者作用
- 2. 三者调用的时序(监听器、过滤器、拦截器)
- 3. 三者的总结
一、监听器
Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener接口的服务器端程序,在javax.servlet.ServletContextListener接口中定义了2种方法。
- void contextInitialized(ServletContextEvent sce) 监听器的初始化
- void contextDestroyed(ServletContextEvent sce) 监听器销毁
public class ServletContextListenerUtil implements ServletContextListener{
//监听器的初始化:随web应用的启动而启动
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("监听器ServletContextListenerUtil初始化");
}
//监听器销毁:随web应用的停止而销毁
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("监听器ServletContextListenerUtil销毁");
}
}
二、过滤器
Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,在javax.servlet.Filter接口中定义了3个方法:
- void init(FilterConfig filterConfig) 用于完成过滤器的初始化
- void destroy() 用于过滤器销毁前,完成某些资源的回收
- void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) 实现过滤功能,该方法对每个请求增加额外的处理
1. POM.xml导包
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
2. web.xml配置
<filter>
<filter-name>encodingFilter</filter-name>
<!-- <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> -->
<filter-class>com.cn.util.FilterUtil</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3. Filter过滤器编程
public class FilterUtil implements Filter{
@SuppressWarnings("unused")
private FilterConfig filterConfig;
//初始化:web服务器启动,就以及初始化了,随时等待过滤对象出现!
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
System.out.println("过滤器Filter初始化");
}
//Chain : 链
/*
1. 过滤中的所有代码,在过滤特定请求的时候都会执行
2. 必须要让过滤器继续同行
chain.doFilter(request,response);
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException("FilterUtil just supports HTTP requests");
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpRequest.setCharacterEncoding(this.filterConfig.getInitParameter("encoding"));
httpResponse.setCharacterEncoding(this.filterConfig.getInitParameter("encoding"));
chain.doFilter(httpRequest, httpResponse); //让我们的请求继续走,如果不写,程序到这里就被拦截停止!
}
//销毁:web服务器关闭的时候,过滤器会销毁
@Override
public void destroy() {
System.out.println("过滤器Filter销毁");
}
}
三、拦截器
在springmvc中,定义拦截器要实现HandlerInterceptor接口,并实现该接口中提供的三个方法
preHandle:原始方法调用前执行
- 参数:
- request:请求对象
- response:响应对象
- handler:被调用的处理器对象
- 返回值:
- 返回值为true,则执行
- 返回值为false,则不执行
postHandler:原始方法调用后执行
- 参数:
- request:请求对象
- response:响应对象
- handler:被调用的处理器对象
- modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行跳
afterCompletion:原始方法调用完成后执行
- 参数:
- request:请求对象
- response:响应对象
- handler:被调用的处理器对象
- ex:异常对象
1. 定义拦截器
@Component //注意当前类必须受Spring容器控制
//定义拦截器类,实现HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
@Override
// 原始方法调用前执行的内容
// 返回值类型可以拦截控制的执行,true放行,false终止
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle..." + contentType);
//获取session中的数据
Object employee = request.getSession().getAttribute("employee");
//若为空,不放行,且写回页面指定数据
if (employee == null) {
R r = R.error("NOTLOGIN");
response.getWriter().print(JSON.toJSON(r));
return false;
}
return true;
}
@Override
// 原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override
// 原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
2. 配置加载拦截器
方式一:可以继承WebMvcConfigurationSupport,但是默认静态资源路径不好使,必须重新映射
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private MyInterceptor myInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
// 配置拦截器
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**") // 需要拦截的路径(/** 拦截所有路径)
.excludePathPatterns("/employee/login","/backend/**","/front/**");//放行静态资源和登陆资源;
}
}
方式二:可以实现WebMvcConfigurer接口,默认静态资源路径好使.还可以重新映射
@Configuration
// 实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class MvcConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
@Override
// 拦截器 添加拦截器并设定拦截的访问路径, 路径可以通过可变参数设置多个
/**
* addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例
* addPathPatterns:用于设置拦截器的过滤路径规则;addPathPatterns("/**")对所有请求都拦截
* excludePathPatterns:用于设置不需要拦截的过滤规则
* 拦截器主要用途:进行用户登录状态的拦截,日志的拦截等。
*/
pulbic void addInterceptors(InterceptorRegistry registry) {
// 配置拦截器
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**")// 需要拦截的路径(/** 拦截所有路径)
.excludePathPatterns("/employee/login","/backend/**","/front/**");//放行静态资源和登陆资源;
}
}
3. 新建页面的存放地点
方式一:我们可以查看WebProperties类的源码,看到静态资源可以存在于以下类路径下的几个路径中任意一个
- /META-INF/resources/
- /resources/
- /static/
- /public/
方式二:我们也可以将路径放在类路径下,通过mvc的配置类放行静态资源
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
@Override
// 拦截器 添加拦截器并设定拦截的访问路径, 路径可以通过可变参数设置多个
/**
* addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例
* addPathPatterns:用于设置拦截器的过滤路径规则;addPathPatterns("/**")对所有请求都拦截
* excludePathPatterns:用于设置不需要拦截的过滤规则
* 拦截器主要用途:进行用户登录状态的拦截,日志的拦截等。
*/
pulbic void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/employee/login","/backend/**","/front/**");//放行静态资源和登陆资源;
}
@Override
// 设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
/**
* addResoureHandler:指的是对外暴露的访问路径
* addResourceLocations:指的是内部文件放置的目录
*/
pulbic void addResourceHandlers(ResourceHandlerRegistry registry) {
// 当访问/XXX/????时候,从/xxx目录下查找内容
// 1、注册backend静态资源处理方式 **匹配多级路径
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
// 2、注册front静态资源处理方式
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
}
四、过滤器、监听器、拦截器
1. 三者作用
- 监听器(Listener):当一个事件发生的时候,你希望获得这个事件发生的详细信息,而并不想干预这个事件本身的进程,这就要用到监听器。
- 过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。
- 拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。
2. 三者调用的时序(监听器、过滤器、拦截器)
- 监听器(Listener):随web应用的启动而启动 ,随web应用的销毁而销毁,所以贯穿整个Web服务 。
- 过滤器(Filter):首先检测URL是符合过滤器的Servlet映射,如果符合就过滤,即执行过滤器代码。所以是在进入Servlet之前。
- 拦截器(Interceptor):preHandle、postHandler、afterCompletion方法表明,拦截器是在Servlet中执行的。
3. 三者的总结
- 监听器:从用户访问到响应返回,整个Web服务过程。负责监听发生的事件,做出相应动作。
- 过滤器:在进入Servlet之前,判断能不能进入Servlet。
- 拦截器:在进入Servlet之后,对方法进行补充增强,有点像AOP