当前位置: 首页 > news >正文

过滤器,监听器,拦截器的原理与在Servlet和Spring的应用

在Java Web的开发中,最原始和初期的学习都是从Servlet开始的,Servlet是Java最为耀眼的技术,也是Java EE的技术变革。目前大火主流的框架spring boot也的spring mvc部分也是基于拓展servlet完成的。回到之前的文章spring 实现了对servlet的封装,来构造控制器controller的过程:Spring MVC框架基础知识,以及servlet的相关知识

在Java Web开发的过程中除了servlet还有比较重要的有拦截器和过滤器,监听器。它们具体作用如下:

  1. servlet :web容器是一种运行服务器端的java应用程序,具有独立于平台和协议的特性,并且可以动态的生成web页面,它工作在客户端请求与服务器响应的中间层。

  2. filter:过滤器是一个可以复用的代码片段,可以用来转换HTTP请求、响应和头信息。Filter不像Servlet,它不能产生一个请求或者响应,它只是修改对某一资源的请求,或者修改从某一的响应。

  3. listener:监听器,listener主要用来监听使用。通过listener可以监听web服务器中某一个执行动作,并根据 其要求作出相应的响应。

  4. interceptor: 拦截器主要用于拦截程序并对程序作出相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。

  5. servlet、filter、listener在ssm中配置到web.xml中,interceptor不配置到web.xml中。spring的拦截器配置到spring.xml中。在spring boot大多是通过配置类注入。它们的关系如下图所示:

在这里插入图片描述

servlet学习网站

过滤器

Servlet 过滤器是可用于 Servlet 编程的 Java 类,有以下目的:

  • 在客户端的请求访问后端资源之前,拦截这些请求。
  • 在服务器的响应发送回客户端之前,处理这些响应。

根据规范建议的各种类型的过滤器:

(1)身份验证过滤器(Authentication Filters)。
(2)数据压缩过滤器(Data compression Filters)。
(3)加密过滤器(Encryption Filters)。
(4)触发资源访问事件过滤器。
(5)图像转换过滤器(Image Conversion Filters)。
(6)日志记录和审核过滤器(Logging and Auditing Filters)。
(7)mime-TYPE 链过滤器(MIME-TYPE Chain Filters)。
(8)标记化过滤器(Tokenizing Filters)。
(9)XSL/T 过滤器(XSL/T Filters),转换 XML 内容。
过滤器被部署在部署描述符文件 web.xml 中,然后映射到您的应用程序的部署描述符中的 Servlet 名称或 URL 模式。

当 Web 容器启动 Web 应用程序时,它会为您在部署描述符中声明的每一个过滤器创建一个实例。该过滤器执行的顺序是按它们在部署描述符中声明的顺序。

在这里插入图片描述

Servlet 过滤器实例:

  • 生产过滤器Filter和Web容器servlet

过滤器是包裹Servlet因此两者都必须存在

//servlet
//导入必需的 java 库
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebServlet("/demo")//扩展 HttpServlet 类
public class DemoServlet extends HttpServlet {// 处理 GET 方法请求的方法public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{// 设置响应内容类型response.setContentType("text/HTML;charset=UTF-8");PrintWriter out = response.getWriter();String title = "HTTP Header 请求实例";String docType ="<!DOCTYPE html> \n";out.println(docType +"<html>\n" +"<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+"<body bgcolor=\"#f0f0f0\">\n" +"<h1 align=\"center\">" + title + "</h1>\n" +"<table width=\"100%\" border=\"1\" align=\"center\">\n" +"<tr bgcolor=\"#949494\">\n" +"<th>Header 名称</th><th>Header 值</th>\n"+"</tr>\n");Enumeration headerNames = request.getHeaderNames();while(headerNames.hasMoreElements()) {String paramName = (String)headerNames.nextElement();out.print("<tr><td>" + paramName + "</td>\n");String paramValue = request.getHeader(paramName);out.println("<td> " + paramValue + "</td></tr>\n");}out.println("</table>\n</body></html>");}// 处理 POST 方法请求的方法public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}
//Filter过滤器
// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.Http.*;
import java.util.*;// 实现 Filter 类
public class LogFilter implements Filter  {public void  init(FilterConfig config) throws ServletException {// 获取初始化参数String site = config.getInitParameter("Site"); // 输出初始化参数System.out.println("网站名称: " + site); 
}public void  doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws java.io.IOException, ServletException {// 获取客户机的 IP 地址   String ipAddress = request.getRemoteAddr();// 记录 IP 地址和当前时间戳System.out.println("IP "+ ipAddress + ", Time "+ new Date().toString());// 把请求传回过滤链chain.doFilter(request,response);}public void destroy( ){/* 在 Filter 实例被 Web 容器从服务移除之前调用 */}
}
  • web.xml配置servlet和Filter以及过滤器和web容器的映射关系

//过滤器配置
<filter><filter-name>LoginFilter</filter-name><filter-class>com.test.LogFilter</filter-class><init-param><param-name>Site</param-name><param-value>kubiji在线教程</param-value></init-param>
</filter>//servlet配置<servlet>  <!-- 类名 -->  <servlet-name>DemoServlet</servlet-name>  <!-- 所在的包 -->  <servlet-class>com.=test.DemoServlet</servlet-class>  
</servlet>  
<servlet-mapping>  <servlet-name>DemoServlet</servlet-name>  <!-- 访问的网址 -->  <url-pattern>/demo</url-pattern>  
</servlet-mapping> //Servlet Filter Mapping<filter-mapping><filter-name>LogFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

过滤器的作用范围:

一个过滤器的作用范围与路径配置有关url-pattern可以配置/*所有路径也可以配置某个web容器,所以Web 应用程序可以根据特定的目的定义若干个不同的过滤器链:

<filter><filter-name>LogFilter</filter-name><filter-class>com.kubiji.test.LogFilter</filter-class><init-param><param-name>test-param</param-name><param-value>Initialization Paramter</param-value></init-param>
</filter><filter><filter-name>AuthenFilter</filter-name><filter-class>com.kubiji.test.AuthenFilter</filter-class><init-param><param-name>test-param</param-name><param-value>Initialization Paramter</param-value></init-param>
</filter><filter-mapping><filter-name>LogFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping><filter-mapping><filter-name>AuthenFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

过滤器的应用顺序:

web.xml 中的 filter-mapping 元素的顺序决定了 Web 容器应用过滤器到 Servlet 的顺序。若要反转过滤器的顺序,您只需要在 web.xml 文件中反转 filter-mapping 元素即可。

SpringMVC的过滤器位于spring-web-[xxx].jar工具包下:

在这里插入图片描述
如上所示的spring-web.jar包结构所示, Spring的web包中中提供有很多过滤器,这些过滤器位于org.springframework.web.filter并且理所当然地实现了javax.servlet.Filter

不过实现的方式有以下几类:

    (1) 直接实现Filter,这一类过滤器只有CompositeFilter;(2) 继承抽象类GenericFilterBean,该类实现了javax.servlet.Filter,这一类的过滤器只有一个,即DelegatingFilterProxy;(3) 继承抽象类OncePerRequestFilter,该类为GenericFilterBean的直接子类,这一类过滤器包括CharacterEncodingFilter、HiddenHttpMethodFilter、HttpPutFormContentFilter、RequestContextFilter和ShallowEtagHeaderFilter;(4) 继承抽象类AbstractRequestLoggingFilter,该类为OncePerRequestFilter的直接子类,这一类过滤器包括CommonsRequestLoggingFilter、Log4jNestedDiagnosticContextFilter和ServletContextRequestLoggingFilter。

过滤器放在容器结构的什么位置?

过滤器放在web资源之前,可以在请求抵达它所应用的web资源(可以是一个Servlet、一个Jsp页面,甚至是一个HTML页面)之前截获进入的请求,并且在它返回到客户之前截获输出请求。Filter:用来拦截请求,处于客户端与被请求资源之间,目的是重用代码。Filter链,在web.xml中哪个先配置,哪个就先调用。在filter中也可以配置一些初始化参数。

Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。

  1. 过滤器触发时机:

过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。

总结:过滤器包裹住servlet,servlet包裹住拦截器。

  1. 过滤器的触发时机是容器后,servlet之前,所以过滤器的doFilter( ServletRequest request, ServletResponse response, FilterChain chain)的入参是ServletRequest ,而不是httpservletrequest。因为过滤器是在httpservlet之前。
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("before...");chain.doFilter(request, response);System.out.println("after...");
}

chain.doFilter(request, response)这个方法的调用作为分水岭。事实上调用Servlet的doService()方法是在chain.doFilter(request, response)这个方法中进行的。

  1. 过滤器是JavaEE标准,采用函数回调的方式进行。是在请求进入容器之后,还未进入Servlet之前进行预处理,并且在请求结束返回给前端这之间进行后期处理。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Spring boot的过滤器

在Spring中,过滤器是配置声明在web.xml文件中的,所有的过滤器在web.xml(web容器的配置文件)中定义,springboot中,web.xml文件消失。各种配置被Java类取代。@Configuration注解标记配置类,代替xml配置文件。

因此过滤器也通过注解注入到IOC容器中,注解@WebFilter声明一个过滤器,里面的参数,filterName 为过滤器名字,urlPatterns 为过滤器的范围,initParams 为过滤器初始化参数。

@Order(1)
@WebFilter(filterName = "piceaFilter", urlPatterns = "/*" , initParams = {@WebInitParam(name = "URL", value = "http://localhost:8080")})

使用包扫描@ServletComponentScan("com.example.demofilter.filter")在启动类自动注册Filter。

@Order(1)
@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("初始化过滤器");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("before filter");filterChain.doFilter(servletRequest,servletResponse);System.out.println("after filter");}@Overridepublic void destroy() {System.out.println("过滤器被销毁了");}

@WebFilter注解,filterName属性表示filter的名称,urlPatter表示要拦截的URL资源,可以是一个或者多个。用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。该注解具有下表给出的一些常用属性 ( 以下所有属性均为可选属性,但是 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值

@Order(1)表示如果有多个拦截器的话就是设置这个拦截器的运行等级,数字越小,越先执行。

@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean registFilter(){FilterRegistrationBean registrationBean = new FilterRegistrationBean();registrationBean.setFilter(new MyFilter());registrationBean.addUrlPatterns("/*");registrationBean.setName("Filter1");registrationBean.setOrder(1);return registrationBean;}
}

@ServletComponentScan:在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码。

拦截器

拦截器方法都是通过代理的方式来调用的,拦截器是基于java反射机制来实现的。

在这里插入图片描述
第一个不是,第二个才是,Interceptor是spring中特有的概念。在 Spring中,当请求发送到 Controller 时,在被Controller处理之前,它必须经过 Interceptors(0或多个)。Spring Interceptor是一个非常类似于Servlet Filter 的概念 。

在这里插入图片描述
在这里插入图片描述

如下案例:

public class LogInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {long startTime = System.currentTimeMillis();System.out.println("brefore login --- ");System.out.println("Request URL: " + request.getRequestURL());System.out.println("Start Time: " + System.currentTimeMillis());request.setAttribute("startTime", startTime);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("login --- ");System.out.println("Request URL: " + request.getRequestURL());}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("after loggin --- ");long startTime = (Long) request.getAttribute("startTime");long endTime = System.currentTimeMillis();System.out.println("Request URL: " + request.getRequestURL());System.out.println("End Time: " + endTime);System.out.println("Time Taken: " + (endTime - startTime));}
}
@Configuration
public class MyInterceptorConfig extends WebMvcConfigurationSupport {@Overrideprotected void addInterceptors(InterceptorRegistry registry) {// 将上面自定义好的拦截器添加进去。registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");super.addInterceptors(registry);}
}

Interceptor的拦截范围其实就是Controller方法,它实际上就相当于基于AOP的方法拦截。因为Interceptor只拦截Controller方法,所以要注意,返回ModelAndView并渲染后,后续处理就脱离了Interceptor的拦截范围。

一个Interceptor必须实现HandlerInterceptor接口,可以选择实现preHandle()、postHandle()和afterCompletion()方法。preHandle()是Controller方法调用前执行,postHandle()是Controller方法正常返回后执行,而afterCompletion()无论Controller方法是否抛异常都会执行,参数ex就是Controller方法抛出的异常(未抛出异常是null)

使用Interceptor

过滤器和拦截器的区别:

拦截器InterceptorFilter过滤器一样,它俩都是面向切面编程——AOP 的具体实现
拦截器是基于java的反射机制的,而过滤器是基于函数回调。
拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

在这里插入图片描述

拦截器的概念

SpringMVC 中的Interceptor 拦截器的主要作用就是拦截用户的 url 请求,并在执行 handler 方法的前中后加入某些特殊请求。SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆等。

在这里插入图片描述
在这里插入图片描述

监听器

Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等。

监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。

监听器入门

Servle监听器
在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别 ServletContext, HttpSession和ServletRequest这三个域对象。servlet监听器的注册不是直接注册在事件源上,而是由WEB容器负责注册,开发人员只需在web.xml文件中使用标签配置好监听器。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

http://www.lryc.cn/news/22401.html

相关文章:

  • minio spring boot 秒传、分片上传、断点续传文件实现
  • MTK平台使用Omnipeek分析空口协议讲解
  • string和自动推断类型
  • 【软件测试】从功能到自动化测试,测试人的进阶之路细节,这些必不可少......
  • C语言青蛙跳台阶【图文详解】
  • 笔记(五)——list容器的基础理论知识
  • 浅谈网络中接口幂等性设计问题
  • 《C Primer Plus》第13章复习题与编程练习
  • 计算机SCI论文应该怎么作图? - 易智编译EaseEditing
  • 【一】kubernetes集群部署
  • Docker安装Redis
  • 在shell中执行一条可执行程序(./a.out) 系统执行的过程
  • 【ArcGIS Pro二次开发】(10):属性表字段(field)的修改
  • 数据结构与算法—散列表
  • 计算机网络笔记、面试八股(一)—— TCP/IP网络模型
  • Servlet笔记(18):国际化
  • kibana搭建(windowslinux)
  • (pytorch进阶之路)Informer
  • 关键词聚类和凸现分析-实战1——亚急性甲状腺炎的
  • 二叉树——二叉搜索树中的众数
  • 安装_配置参数解读_集群安装配置_启动选举_搭建启停脚本---大数据之ZooKeeper工作笔记004
  • RTMP的工作原理及优缺点
  • 【数据结构与算法】——第八章:排序
  • 在linux中web服务器的搭建与配置
  • 《Python机器学习》基础代码2
  • 如何基于MLServer构建Python机器学习服务
  • 9.1 IGMPv1实验
  • 软考高级系统分析师系列论文之十:论实时控制系统与企业信息系统的集成在通信业应用
  • NIO与零拷贝
  • 【PAT甲级题解记录】1151 LCA in a Binary Tree (30 分)