文章目录
- Java Web三大组件
- 一、Filter概述
- 二、Filter开始
- 1_过滤器API介绍
- 2_过滤器开发步骤
- 3_代码实现
- 4_过滤器执行流程小结
- 三、使用细节
- 1_生命周期
- 2_拦截路径
- 3_过滤器链
- 四、Listener
- 1_Listener概述
- 2_监听器举例
- 3_Listener开始
- 4_案例:模拟spring框架
Java Web三大组件
- 组件: 是一个系统的组成部件
-
javaweb组件 : javaweb项目的组成部件
- servlet
- filter
- listener
组件 | 作用 | 实现接口 |
---|---|---|
Servlet | Server Applet小应用程序,在JavaWeb中主要做为控制器来使用,可以处理用户的请求并且做出响应 | javax.servlet.Servlet |
Filter | 过滤器,对用户发送的请求或响应进行集中处理,实现请求的拦截 | javax.servlet.Filter |
Listener | 监听器,在Web执行过程中,监听一些事件,当相应事件发生时, 进行处理 |
javax.servlet.XxxListener 每个事件有一个接口 |
一、Filter概述
生活中的过滤器
净水器、空气净化器、地铁安检
web中的过滤器
当用户访问服务器资源时,过滤器将请求拦截下来,完成一些通用的操作
F i l t e r Filter Filter 的作用
- 拦截客户端对web资源的请求 (重要!)
- 拦截web资源对客户端的响应
应用场景
如:登录验证、统一编码处理、敏感字符过滤
二、Filter开始
1_过滤器API介绍
F i l t e r Filter Filter 表示过滤器接口,我们想使用该接口必须自定义类实现接口并实现该接口中的所有抽象方法。
javax.Servlet.Filter
接口下面的三个方法:
方法 | 说明 |
---|---|
void init(FilterConfig filterConfig) |
过滤器对象创建的时候调用的方法 |
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) |
执行过滤的方法,每次访问被拦截的资源都会执行该方法 |
void destory() |
过滤器销毁的时候调用的方法 |
注意:doFilter
第三个参数:FilterChain 表示过滤器链接口。
放行:使用 FilterChain 对象调用 FilterChain 中的方法:chain.doFilter(request,response);
即可以让浏览器访问服务器资源。
不放行,那么不写上述代码,即不让浏览器访问服务器资源。
2_过滤器开发步骤
1.自定义过滤器类实现过滤器接口 F i l t e r Filter Filter
2.在自定义类中实现过滤器接口 F i l t e r Filter Filter中的所有抽象方法
3.在doFilter
方法体中书写拦截资源的代码
F i l t e r Filter Filter 过滤器接口的关键方法说明:
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
参数:
-
request:表示请求对象,不满足 h t t p http http协议
-
response:表示响应对象,不满足 h t t p http http协议
-
chain:属于 FilterChain 的接口,表示过滤器链。
FilterChain 接口中具有一个放行方法:
void doFilter(ServletRequest request, ServletResponse response)
-
如果放行,希望浏览器可以访问拦截的资源则执行该方法
filterChain.doFilter(servletRequest,servletResponse);
-
如果不放行,不希望浏览器访问拦截的资源则不执行该方法
-
4.配置过滤器
5.访问被拦截的资源
3_代码实现
过滤器类:
import javax.servlet.*;
import java.io.IOException;
//1.自定义过滤器类实现过滤器接口Filter
public class MyFilter implements Filter {
//2.在自定义类中实现过滤器接口Filter中的所有抽象方法
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 不要调用父类的初始化方法否则报错
// Filter.super.init(filterConfig);
}
//3.在doFilter方法体中书写拦截资源的代码
//每次访问被过滤的资源都要执行该方法
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("执行过滤器了...");
//不放行
/*
Filter过滤器接口的:
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
参数:
request:表示请求对象,不满足http协议
response:表示响应对象,不满足http协议
chain:属于FilterChain的接口,表示过滤器链。
FilterChain接口中具有一个放行方法:
void doFilter(ServletRequest request, ServletResponse response)
如果放行,希望浏览器可以访问拦截的资源则执行该方法
如果不放行,不希望浏览器访问拦截的资源则不执行该方法
*/
//放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
web.xml
:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Archetype Created Web Application</display-name>
<!--配置过滤器-->
<!--表示关联的过滤器类-->
<filter>
<filter-name>myFilter</filter-name>
<!--过滤器类的全路径,底层获取这里使用反射技术调用无参构造方法创建过滤器类的对象-->
<filter-class>com.example.sh.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<!--配置被拦截的资源-->
<url-pattern>/filter01.html</url-pattern>
</filter-mapping>
</web-app>
被拦截的页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>来拦截我啊</h1>
</body>
</html>
小结:
1.配置过滤器有两种方式:
-
xml
版本:<!--配置过滤器--> <!--表示关联的过滤器类--> <filter> <filter-name>myFilter</filter-name> <!--过滤器类的全路径,底层获取这里使用反射技术调用无参构造方法创建过滤器类的对象--> <filter-class>com.example.sh.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter-name> <!--配置被拦截的资源--> <url-pattern>/filter01.html</url-pattern> </filter-mapping>
-
注解版本配置
使用注解必须去掉
xml
版本。
4_过滤器执行流程小结
- 用户发送请求,请求Web资源(包括
html, jsp, servlet
等)。 - 如果Web资源的地址,是
f
i
l
t
e
r
filter
filter 要拦截的地址,请求将先经过
f
i
l
t
e
r
filter
filter,并执行
doFilter()
。 -
doFilter()
方法中如果调用filterChain.doFilter()
,则允许请求访问下一个Web资源。 - 访问Web资源,响应回来会再次经过 f i l t e r filter filter,执行过滤器中的代码,到达浏览器端。
三、使用细节
1_生命周期
生命周期:指的是一个对象从生(创建)到死(销毁)的一个过程
// 初始化方法
public void init(FilterConfig config);
// 执行拦截方法
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain);
// 销毁方法
public void destroy();
-
创建
服务器启动项目加载,创建 f i l t e r filter filter对象,执行
init
方法(只执行一次) -
运行(过滤拦截)
用户访问被拦截目标资源时,执行
doFilter
方法 -
销毁
服务器关闭时,销毁 f i l t e r filter filter对象,执行
destroy
方法(只执行一次) -
补充:
过滤器一定是优先于
servlet
创建的,后于 S e r v l e t Servlet Servlet 销毁复习:
servlet
默认是第一次访问的时候创建
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/*
Filter的生命周期方法
1. init
web服务器启动时,此方法运行,就运行一次(早于Servlet)
2. doFilter
当请求经过过滤器,此方法就会运行(每经过一次,就运行一次) (早于servlet的service方法)
3. destroy
tomcat关闭, 此方法运行一次 (晚于servlet的destroy)
*/
@WebFilter("/MyFilterLife")
public class MyFilterLife implements Filter {
public MyFilterLife() {
System.out.println("MyFilterLife的构造方法被调用了..........");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilterLife init");
}
//当请求经过过滤器,此方法就会运行(每经过一次,就运行一次)
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("MyFilterLife doFilter");
//请求放行 (相当于请求转发)
chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("MyFilterLife destroy");
}
}
总结:
- 过滤器是在
t
o
m
c
a
t
tomcat
tomcat启动的时候
t
o
m
c
a
t
tomcat
tomcat调用过滤器类中的无参构造方法创建对象,使用对象调用
init
方法,只会执行一次 - 当使用浏览器访问被过滤的资源的时候就会执行过滤器
F
i
l
t
e
r
Filter
Filter中的
doFilter
方法,访问一次就会执行一次doFilter
方法 - 当关闭
t
o
m
c
a
t
tomcat
tomcat服务器就会使用对象调用销毁方法
destroy
,只会执行一次 - 过滤器优先于访问的资源执行
2_拦截路径
在开发时,我们可以指定过滤器的拦截路径来定义拦截目标资源的范围
-
精准匹配
用户访问指定目标资源(
/demo01.html
)时,过滤器进行拦截 -
目录匹配
用户访问指定目录下(
/user/*
)所有资源时,过滤器进行拦截 -
后缀匹配
用户访问指定后缀名(
*.html
)的资源时,过滤器进行拦截,不能加/
-
匹配所有
用户访问该网站所有资源(
/*
)时,过滤器进行拦截
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
//@WebFilter({"/xx","/yy"})
//@WebFilter("/xx") // 精准匹配
//@WebFilter("/user/*") // 目录匹配
//@WebFilter("*.do") // 后缀匹配
@WebFilter("/*") // 匹配所有
public class MyFilterPath implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter");
}
@Override
public void destroy() {
}
}
注意: 在过滤器中,如果多个过滤器过滤同一个资源,那么要执行所有满足条件的过滤器。
3_过滤器链
在一次请求中,若我们请求匹配到了多个 f i l t e r filter filter,通过请求就相当于把这些 f i l t e r filter filter串起来了,形成了过滤器链。
问题:如果多个过滤器都对相同路径进行匹配,执行顺序该是什么?
F i l t e r Filter Filter 默认是按照字母顺序执行的,如果过滤器名字第一个字母相同,再看过滤器名字的第二个字母,以此类推。从而形成一个执行链条。
前提:多个过滤器过滤同一个资源,并且多个过滤器是在同一包下。
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/apple")
public class AFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
System.out.println("AFilter....放行前");
chain.doFilter(request, response);
System.out.println("AFilter....放行后");
}
public void init(FilterConfig config) throws ServletException {
}
}
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/apple")
public class BFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
System.out.println("BFilter....放行前");
chain.doFilter(request, response);
System.out.println("BFilter....放行后");
}
public void init(FilterConfig config) throws ServletException {
}
}
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/apple")
public class AppleServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("AppleServlet....");
}
}
总结:
-
如果同一个包下,多个过滤器拦截同一个资源,那么按照过滤器类的名字字母升序来依次执行(针对注解开发)
AFilter ---- BFilter
-
执行完拦截资源后依次在按照相反顺序执行
-
如果是
xml
配置方式,那么按照从上往下配置的顺序执行
四、Listener
1_Listener概述
说明:
javaweb中的监听器是监听 S e r v l e t C o n t e x t ServletContext ServletContext、