前言
最直观的感受是Filter是在servlet的外层,而Interceptor是在Servlet的内层,当然没有这么简单。
一、监听器、拦截器、过滤器的区别
1.1 监听器
listener就是对项目起到监听的作用,它能感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化;监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。
其主要可用于以下方面:
- 统计在线人数和在线用户
- 系统启动时加载初始化信息
- 统计网站访问量
- 记录用户访问路径。
1.2 过滤器
主要的用途是过滤字符编码、做一些业务逻辑判断、URL级别的权限控制,敏感词汇的过滤,等。只要你在web.xml文件配置好要拦截的客户端请求(老方法),它都会帮你拦截到请求,此时你就可以对请求或响应(Request、Response)统一设置编码,简化操作;同时还可进行逻辑判断,如用户是否已经登陆、有没有权限访问该页面等等工作。它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。
- 最常见就是springmvc的编码过滤器了。还有一些其他跨域过滤器。下面是基于web.xml配置,现在大多以注解配置为主
<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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
1.3 拦截器
Interceptor 在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。比如日志,安全等。一般拦截器方法都是通过动态代理的方式实现。可以通过它来进行权限验证,或者判断用户是否登陆,或者是像12306 判断当前时间是否是购票时间。
- 拦截器不是在web.xml,比如springmvc的配置文件中配置(老方法)
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean id="commonInterceptor" class="org.shop.interceptor.CommonInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
1.4 小总结
1.4.1 执行顺序
context-param (由外到内)
-->listener(监听器)
-->filter(过滤器)
-->Servlet
-->interceptor(拦截器)
-->Controller(控制器)
它们之间的执行顺序
- 监听器是容器启动时就会触发
- 过滤器在请求到底Action之前执
- 拦截器则是请求到达action之后执行的。
注意:action是之前的struts2框架叫法,也就是如今的Controller层
1.4.2 拦截器和过滤器的区别
- 拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调,我们需要实现的filter接口中doFilter方法就是回调函数。
- Filter需要在web.xml中配置,依赖于Servlet容器。而interceptor与servlet容器无关,Interceptor需要在SpringMVC中配置,依赖于框架。拦截器本身就是在servlet内部的。
- Filter的过滤范围比Interceptor大,Filter除了过滤请求外通过通配符可以保护页面,图片,文件等等,而Interceptor只能过滤请求。
- 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
Filter pre --->dispatcher--->preHandle-->controller-->postHandle--->afterCompletion--->Filter After
1.4.3 使用技巧
- 需要监听到项目中的一些信息,并且不需要对流程做更改时,用监听器;
- 当需要过滤掉其中的部分信息,只留一部分时,就用过滤器;
- 当需要对其流程进行更改,做相关的记录时用拦截器。
相关文章
二、拦截器的应用
2.1 知识背景
WebMvcConfigurer配置类其实是Spring
内部的一种配置方式,采用JavaBean
的形式来代替传统的xml
配置文件形式进行针对框架个性化定制,可以自定义一些Handler,Interceptor,ViewResolver,MessageConverter。基于java-based方式的spring mvc配置,需要创建一个配置类并实现WebMvcConfigurer
接口;
在Spring Boot 1.5版本都是靠重写WebMvcConfigurerAdapter的方法来添加自定义拦截器,消息转换器等。SpringBoot 2.0 后,该类被标记为@Deprecated(弃用)。官方推荐直接实现WebMvcConfigurer或者直接继承WebMvcConfigurationSupport,
- 方式一实现WebMvcConfigurer接口(推荐)
- 方式二继承WebMvcConfigurationSupport类,具体实现可看这篇文章:
2.2 WebMvcConfigurer接口
public interface WebMvcConfigurer {
// 匹配路径
void configurePathMatch(PathMatchConfigurer var1);
// 配置内容裁决的一些选项
void configureContentNegotiation(ContentNegotiationConfigurer var1);
void configureAsyncSupport(AsyncSupportConfigurer var1);
=//默认静态资源处理器
void configureDefaultServletHandling(DefaultServletHandlerConfigurer var1);
void addFormatters(FormatterRegistry var1);
// 拦截器配置
void addInterceptors(InterceptorRegistry var1);
// 静态资源处理
void addResourceHandlers(ResourceHandlerRegistry var1);
// 解决跨域问题
void addCorsMappings(CorsRegistry var1);
// 视图跳转控制器(thymeleaf/jsp/freemaker/velocity等用的居多)
void addViewControllers(ViewControllerRegistry var1);
// 配置视图解析器
void configureViewResolvers(ViewResolverRegistry var1);
// 方法非法参数解析
void addArgumentResolvers(List<HandlerMethodArgumentResolver> var1);
// 返回值处理
void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> var1);
// 消息转换器
void configureMessageConverters(List<HttpMessageConverter<?>> var1);
void extendMessageConverters(List<HttpMessageConverter<?>> var1);
//异常解析器
void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> var1);
void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> var1);
Validator getValidator();
MessageCodesResolver getMessageCodesResolver();
}
其中主要方法具体使用方法可以参考这个篇文章:
- addInterceptors:拦截器
- addViewControllers:页面跳转
- addResourceHandlers:静态资源
- configureDefaultServletHandling:默认静态资源处理器
- configureViewResolvers:视图解析器
- configureContentNegotiation:配置内容裁决的一些参数
- addCorsMappings:跨域
- configureMessageConverters:信息转换器
2.3 拦截器的使用
- 实现 HandlerInterceptor 接口定义拦截器
WebMvcConfigurer使用这个接口配置拦截器
案例:
@Component
public class SessionInterceptor extends HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return super.preHandle(request, response, handler);
}
}
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
private SessionInterceptor sessionInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(sessionInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/XXXXXX.json");
}
}
2.4 注入Bean的方式实现 SpringBoot添加自定义消息转换器
三、过滤器的应用
过滤器是对数据进行过滤,预处理过程,当我们访问网站时,有时候会发布一些敏感信息,发完以后有的会用*替代,还有就是登陆权限控制等,一个资源,没有经过授权,肯定是不能让用户随便访问的,这个时候,也可以用到过滤器。过滤器的功能还有很多,例如实现URL级别的权限控制、压缩响应信息、编码格式等等。
过滤器依赖servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤。
实现类型
- 实现springboot中javax.servlet.Filter原生接口的实现
- 继承Spring内置的OncePerRequestFilter抽象类
区别
- 实现springboot中javax.servlet.Filter原生接口的实现在Servlet服务器内部进行页面跳转请求转发和重定向时也会经过过滤器
- 继承Spring内置的OncePerRequestFilter抽象类【一次请求中只过滤一次】就避免了内部请求过滤,只过滤外部的一些请求
主要应用场景:
- @Order(1):表示过滤器的顺序,假设我们有多个过滤器,你如何确定过滤器的执行顺序?这个注解就是规定过滤器的顺序。
- @WebFilter:表示这个class是过滤器。里面的参数,filterName 为过滤器名字,urlPatterns 为过滤器的范围,initParams 为过滤器初始化参数。
init : filter对象只会创建一次,init方法也只会执行一次。
doFilter : 主要的业务代码编写方法,可以多次重复调用
destroy : 在销毁Filter时自动调用(程序关闭或者主动销毁Filter)。
下面简单的说说Spring Boot里面如何增加过滤器。
(1) 使用注解实现过滤器
- 启动类中增加注解,自动注册Filter
@ServletComponentScan :在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码。 - 定义过滤器
@Order(1)
@WebFilter(filterName = "piceaFilter", urlPatterns = "/*" , initParams = {
@WebInitParam(name = "URL", value = "http://localhost:8080")})
public class PiceaFilter implements Filter {
private String url;
/**
* 可以初始化Filter在web.xml里面配置的初始化参数
* filter对象只会创建一次,init方法也只会执行一次。
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.url = filterConfig.getInitParameter("URL");
System.out.println("我是过滤器的初始化方法!URL=" + this.url + ",生活开始.........");
}
/**
* 主要的业务代码编写方法
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("我是过滤器的执行方法,客户端向Servlet发送的请求被我拦截到了");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("我是过滤器的执行方法,Servlet向客户端发送的响应被我拦截到了");
}
/**
* 在销毁Filter时自动调用。
*/
@Override
public void destroy() {
System.out.println("我是过滤器的被销毁时调用的方法!,活不下去了................" );
}
}
(2)使用配置实现过滤器
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new XssFilter());
registration.addUrlPatterns("/*");
registration.setName("xssFilter");
registration.setOrder(1);
return registration;
}
}
public class XssFilter implements Filter{
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
}
@Override
public void destroy() {
}
}
相关文章
- Spring Boot使用过滤器Filter
- Spring boot 拦截器和过滤器
- XSS过滤JAVA过滤器filter 防止常见SQL注入
三、监听器的应用
监听器也叫Listener,是servlet的监听器,可以用于监听Web应用中某些对象,信息的创建,销毁,增加,修改,删除等动作的发生,然后做出相应的响应处理。当范围对象的状态发生变化时,服务器自动调用监听器对象中的方法,常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等。
监听器大概分为以下几种:
- ServletContextListener:用来监听 ServletContext 属性的操作,比如新增、修改、删除。
- HttpSessionListener:用来监听 Web 应用种的 Session 对象,通常用于统计在线情况。
- ServletRequestListener:用来监听 Request 对象的属性操作。
监听器的使用
我们通过 HttpSessionListener来统计当前在线人数、ip等信息,为了避免并发问题我们使用原子int来计数。
ServletContext,是一个全局的储存信息的空间,它的生命周期与Servlet容器也就是服务器保持一致,服务器关闭才销毁。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。因此我们这里用ServletContext来存储在线人数sessionCount最为合适。
3.1 SpringBoot-事件监听的4种实现方式
- 手工向ApplicationContext中添加监听器
- 将监听器装载入spring容器
- 在application.properties中配置监听器
- 通过@EventListener注解实现事件监听
讲到事件监听,这里我们说下自定义事件和自定义监听器类的实现方式:
- 自定义事件:继承自ApplicationEvent抽象类,然后定义自己的构造器
- 自定义监听:实现ApplicationListener<T>接口,然后实现onApplicationEvent方法
具体使用事例