前言

最直观的感受是Filter是在servlet的外层,而Interceptor是在Servlet的内层,当然没有这么简单。

                                     

java springboot host 过滤器 springboot过滤器作用_拦截器

一、监听器、拦截器、过滤器的区别

  1.1 监听器

  listener就是对项目起到监听的作用,它能感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化;监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。

 其主要可用于以下方面:

  1. 统计在线人数和在线用户
  2. 系统启动时加载初始化信息
  3. 统计网站访问量
  4. 记录用户访问路径。

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层

java springboot host 过滤器 springboot过滤器作用_拦截器_02

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 使用技巧

  1. 需要监听到项目中的一些信息,并且不需要对流程做更改时,用监听器;
  2. 当需要过滤掉其中的部分信息,只留一部分时,就用过滤器;
  3. 当需要对其流程进行更改,做相关的记录时用拦截器。

java springboot host 过滤器 springboot过滤器作用_springboot_03

相关文章

  1. springboot监听器、过滤器和拦截器

二、拦截器的应用

   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();
}

其中主要方法具体使用方法可以参考这个篇文章:

  1. addInterceptors:拦截器
  2. addViewControllers:页面跳转
  3. addResourceHandlers:静态资源
  4.  configureDefaultServletHandling:默认静态资源处理器
  5.  configureViewResolvers:视图解析器
  6.  configureContentNegotiation:配置内容裁决的一些参数
  7.  addCorsMappings:跨域
  8.  configureMessageConverters:信息转换器

2.3 拦截器的使用

  1. 实现 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");
    }
}
  1. SpringBoot之HandlerInterceptorAdapter
  2. HandlerMethodArgumentResolver用于统一获取当前登录用户

2.4  注入Bean的方式实现 SpringBoot添加自定义消息转换器

三、过滤器的应用

         过滤器是对数据进行过滤,预处理过程,当我们访问网站时,有时候会发布一些敏感信息,发完以后有的会用*替代,还有就是登陆权限控制等,一个资源,没有经过授权,肯定是不能让用户随便访问的,这个时候,也可以用到过滤器。过滤器的功能还有很多,例如实现URL级别的权限控制、压缩响应信息、编码格式等等。
过滤器依赖servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤。

实现类型

  1. 实现springboot中javax.servlet.Filter原生接口的实现
  2. 继承Spring内置的OncePerRequestFilter抽象类

区别

  1. 实现springboot中javax.servlet.Filter原生接口的实现在Servlet服务器内部进行页面跳转请求转发和重定向时也会经过过滤器   
  2.  继承Spring内置的OncePerRequestFilter抽象类【一次请求中只过滤一次】就避免了内部请求过滤,只过滤外部的一些请求

主要应用场景:

  1. @Order(1):表示过滤器的顺序,假设我们有多个过滤器,你如何确定过滤器的执行顺序?这个注解就是规定过滤器的顺序。
  2. @WebFilter:表示这个class是过滤器。里面的参数,filterName 为过滤器名字,urlPatterns 为过滤器的范围,initParams 为过滤器初始化参数。

init : filter对象只会创建一次,init方法也只会执行一次。
doFilter : 主要的业务代码编写方法,可以多次重复调用
destroy : 在销毁Filter时自动调用(程序关闭或者主动销毁Filter)。

  下面简单的说说Spring Boot里面如何增加过滤器。

(1)  使用注解实现过滤器

  1. 启动类中增加注解,自动注册Filter
    @ServletComponentScan :在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码。
  2. 定义过滤器
@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() {
    }
}

相关文章

  1. Spring Boot使用过滤器Filter
  2. Spring boot 拦截器和过滤器
  3. 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种实现方式

  1. 手工向ApplicationContext中添加监听器
  2. 将监听器装载入spring容器
  3. 在application.properties中配置监听器
  4. 通过@EventListener注解实现事件监听

讲到事件监听,这里我们说下自定义事件和自定义监听器类的实现方式:

  • 自定义事件:继承自ApplicationEvent抽象类,然后定义自己的构造器
  • 自定义监听:实现ApplicationListener<T>接口,然后实现onApplicationEvent方法

具体使用事例