Filter:一个实现了特殊接口(Filter)的Java类. 实现对请求资源(jsp,servlet,html,)的过滤的功能. 过滤器是一个运行在服务器的程序, 优先于请求资源(Servlet或者jsp,html)之前执行. 过滤器是javaweb技术中最为实用的技术之一
Filter的作用是对目标资源(Servlet,jsp)进行过滤,其应用场景有: 登录权限检查,解决网站乱码,过滤敏感字符等等
实现在请求到达ServletDemo01之前解决请求参数的中文乱码
web.xml代码
<servlet>
<servlet-name>servletDemo01servlet-name>
<servlet-class>com.aqrlmy.ServletDemo01servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletDemo01servlet-name>
<url-pattern>/ServletDemo01url-pattern>
servlet-mapping>
ServletDemo01代码
package com.aqrlmy.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Leevi
* 日期2021-05-18 08:53
*/
public class ServletDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
System.out.println("ServletDemo01接收到了一个请求..."+username);
}
}
前端页面代码
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页title>
head>
<body>
<form action="/webday12/demo01" method="post">
用户名<input type="text" name="username"/><br/>
<input type="submit"/>
form>
body>
html>
如果此时没有Filter,那么客户端发送的请求直接到达ServletDemo01,中文请求参数就会发生乱码
web.xml代码
<filter>
<filter-name>encodingFilterfilter-name>
<filter-class>com.aqrlmy.filter.EncodingFilterfilter-class>
filter>
<filter-mapping>
<filter-name>encodingFilterfilter-name>
<url-pattern>/demo01url-pattern>
filter-mapping>
EncodingFilter代码
package com.aqrlmy.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author Leevi
* 日期2021-05-18 08:56
* 编写过滤器的步骤:
* 1. 写一个类实现Filter接口,并且重写方法
* 2. 在web.xml中配置该过滤器的拦截路径
*/
public class EncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//解决请求参数的乱码
HttpServletRequest request = (HttpServletRequest) req;
request.setCharacterEncoding("UTF-8");
//每次有请求被当前filter接收到的时候,就会执行doFilter进行过滤处理
System.out.println("EncodingFilter接收到了一个请求...");
//这句代码表示放行
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}
Servlet默认在第一次接收请求的时候创建,可以通过
标签配置Servlet在服务器启动的时候创建
Servlet会在服务器关闭或者将项目从服务器上移除的时候销毁
生命周期阶段 | 执行时机 | 生命周期方法 |
---|---|---|
创建对象 | Web应用启动时 | init方法,通常在该方法中做初始化工作 |
拦截请求 | 接收到匹配的请求 | doFilter方法,通常在该方法中执行拦截过滤 |
销毁 | Web应用卸载前 | destroy方法,通常在该方法中执行资源释放 |
过滤器匹配的目的是指定当前过滤器要拦截哪些资源
指定被拦截资源的完整路径:
<filter-mapping>
<filter-name>FilterDemo01filter-name>
<url-pattern>/demo01url-pattern>
filter-mapping>
上述例子表示要拦截映射路径为/demo01
的这个资源
相比较精确匹配,使用模糊匹配可以创建一个Filter就能够覆盖很多目标资源,不必专门为每一个目标资源都创建Filter,提高开发效率。
配置了url-pattern为/user/*之后,请求地址只要是/user开头的那么就会被匹配。
<filter-mapping>
<filter-name>Target02Filterfilter-name>
<url-pattern>/user/*url-pattern>
filter-mapping>
极端情况:/*匹配所有请求
<filter>
<filter-name>Target04Filterfilter-name>
<filter-class>com.aqrlmy.filter.filter.Target04Filterfilter-class>
filter>
<filter-mapping>
<filter-name>Target04Filterfilter-name>
<url-pattern>*.pngurl-pattern>
filter-mapping>
上述例子表示拦截所有以.png
结尾的请求
<filter-mapping>
<filter-name>Target05Filterfilter-name>
<servlet-name>Target01Servletservlet-name>
filter-mapping>
一个请求可能被多个过滤器所过滤,只有当所有过滤器都放行,请求才能到达目标资源,如果有某一个过滤器没有放行,那么请求则无法到达后续过滤器以及目标资源,多个过滤器组成的链路就是过滤器链
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uRcpM3xx-1663643289059)(images/img004.png)]
过滤器链中每一个Filter执行的顺序是由web.xml中filter-mapping配置的顺序决定的。如果某个Filter是使用ServletName进行匹配规则的配置,那么这个Filter执行的优先级要更低
web.xml代码
<servlet>
<servlet-name>servletDemo01servlet-name>
<servlet-class>com.aqrlmy.ServletDemo01servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletDemo01servlet-name>
<url-pattern>/ServletDemo01url-pattern>
servlet-mapping>
ServletDemo01代码
public class ServletDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ServletDemo01接收到了请求...");
}
}
<filter-mapping>
<filter-name>TargetChain03Filterfilter-name>
<url-pattern>/Target05Servleturl-pattern>
filter-mapping>
<filter-mapping>
<filter-name>TargetChain02Filterfilter-name>
<url-pattern>/Target05Servleturl-pattern>
filter-mapping>
<filter-mapping>
<filter-name>TargetChain01Filterfilter-name>
<url-pattern>/Target05Servleturl-pattern>
filter-mapping>
观察者模式是二十三中设计模式之一,它是指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式
监听器:专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。
Servlet监听器:Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext,HttpSession 和HttpServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。
作用:监听ServletContext对象的创建与销毁
方法名 | 作用 |
---|---|
contextInitialized(ServletContextEvent sce) | ServletContext创建时调用 |
contextDestroyed(ServletContextEvent sce) | ServletContext销毁时调用 |
ServletContextEvent对象代表从ServletContext对象身上捕获到的事件,通过这个事件对象可以获取到ServletContext对象。
作用:监听HttpSession对象的创建与销毁
方法名 | 作用 |
---|---|
sessionCreated(HttpSessionEvent hse) | HttpSession对象创建时调用 |
sessionDestroyed(HttpSessionEvent hse) | HttpSession对象销毁时调用 |
HttpSessionEvent对象代表从HttpSession对象身上捕获到的事件,通过这个事件对象可以获取到触发事件的HttpSession对象。
作用:监听ServletRequest对象的创建与销毁
方法名 | 作用 |
---|---|
requestInitialized(ServletRequestEvent sre) | ServletRequest对象创建时调用 |
requestDestroyed(ServletRequestEvent sre) | ServletRequest对象销毁时调用 |
ServletRequestEvent对象代表从HttpServletRequest对象身上捕获到的事件,通过这个事件对象可以获取到触发事件的HttpServletRequest对象。另外还有一个方法可以获取到当前Web应用的ServletContext对象。
作用:监听ServletContext中属性的添加、移除和修改
方法名 | 作用 |
---|---|
attributeAdded(ServletContextAttributeEvent scab) | 向ServletContext中添加属性时调用 |
attributeRemoved(ServletContextAttributeEvent scab) | 从ServletContext中移除属性时调用 |
attributeReplaced(ServletContextAttributeEvent scab) | 当ServletContext中的属性被修改时调用 |
ServletContextAttributeEvent对象代表属性变化事件,它包含的方法如下:
方法名 | 作用 |
---|---|
getName() | 获取修改或添加的属性名 |
getValue() | 获取被修改或添加的属性值 |
getServletContext() | 获取ServletContext对象 |
作用:监听HttpSession中属性的添加、移除和修改
方法名 | 作用 |
---|---|
attributeAdded(HttpSessionBindingEvent se) | 向HttpSession中添加属性时调用 |
attributeRemoved(HttpSessionBindingEvent se) | 从HttpSession中移除属性时调用 |
attributeReplaced(HttpSessionBindingEvent se) | 当HttpSession中的属性被修改时调用 |
HttpSessionBindingEvent对象代表属性变化事件,它包含的方法如下:
方法名 | 作用 |
---|---|
getName() | 获取修改或添加的属性名 |
getValue() | 获取被修改或添加的属性值 |
getSession() | 获取触发事件的HttpSession对象 |
作用:监听ServletRequest中属性的添加、移除和修改
方法名 | 作用 |
---|---|
attributeAdded(ServletRequestAttributeEvent srae) | 向ServletRequest中添加属性时调用 |
attributeRemoved(ServletRequestAttributeEvent srae) | 从ServletRequest中移除属性时调用 |
attributeReplaced(ServletRequestAttributeEvent srae) | 当ServletRequest中的属性被修改时调用 |
ServletRequestAttributeEvent对象代表属性变化事件,它包含的方法如下:
方法名 | 作用 |
---|---|
getName() | 获取修改或添加的属性名 |
getValue() | 获取被修改或添加的属性值 |
getServletRequest () | 获取触发事件的ServletRequest对象 |
作用:监听某个对象在Session域中的创建与移除
方法名 | 作用 |
---|---|
valueBound(HttpSessionBindingEvent event) | 该类的实例被放到Session域中时调用 |
valueUnbound(HttpSessionBindingEvent event) | 该类的实例从Session中移除时调用 |
HttpSessionBindingEvent对象代表属性变化事件,它包含的方法如下:
方法名 | 作用 |
---|---|
getName() | 获取当前事件涉及的属性名 |
getValue() | 获取当前事件涉及的属性值 |
getSession() | 获取触发事件的HttpSession对象 |
作用:监听某个对象在Session中的序列化与反序列化。
方法名 | 作用 |
---|---|
sessionWillPassivate(HttpSessionEvent se) | 该类实例和Session一起钝化到硬盘时调用 |
sessionDidActivate(HttpSessionEvent se) | 该类实例和Session一起活化到内存时调用 |
HttpSessionEvent对象代表事件对象,通过getSession()方法获取事件涉及的HttpSession对象。
ServletContextListener是监听ServletContext对象的创建和销毁的,因为ServletContext对象是在服务器启动的时候创建、在服务器关闭的时候销毁,所以ServletContextListener也可以监听服务器的启动和关闭
将来学习SpringMVC的时候,会用到一个ContextLoaderListener,这个监听器就实现了ServletContextListener接口,表示对ServletContext对象本身的生命周期进行监控。
package com.aqrlmy.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* 包名:com.aqrlmy.listener
*
* @author Leevi
* 日期2021-06-19 10:26
* 编写监听器的步骤:
* 1. 写一个类实现对应的:Listener的接口(这里使用的是ServletContextListener),并且实现它里面的方法
* 1.1 contextInitialized()这个方法在ServletContext对象被创建出来的时候执行,也就是说在服务器启动的时候执行
* 1.2 contextDestroyed()这个方法会在ServletContext对象被销毁的时候执行,也就是说在服务器关闭的时候执行
*
* 2. 在web.xml中注册(配置)监听器
*/
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("在服务器启动的时候,模拟创建SpringMVC的核心容器...");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("在服务器启动的时候,模拟销毁SpringMVC的核心容器...");
}
}
<listener>
<listener-class>com.aqrlmy.listener.ContextLoaderListenerlistener-class>
listener>