文章目录
JavaWeb三大组件
JavaWeb三大组件分别是:Servlet、Filter、Listener
- 它们都是都是JavaEE的接口(规范),同时也是是一种技术,只是后两个不属于JavaEE的核心技术1
- 一般而言我们讲的三大组件都是指部署在Web服务器上实现这三个接口的服务端程序,主要作用就是让Web服务器能够更好地处理来自浏览器发送的请求数据
- Servlet主要用于响应浏览器发送的请求数据
- Filter主要用于对浏览器发送给Servlet的请求数据进行过滤
- Listener主要用于监听域对象的行为
1、Servlet
1.1 Servlet概述
什么是Servlet?
Servlet本质是Java官方提供的一个接口(规范),目的就是为了规范我们开发Servlet程序,同时它和JDBC一样都是JavaEE的核心技术之一1。通常我们讲的Servlet都是指实现了Servlet接口的程序(就是封装好的Servlet接口实现类),它是运行在服务端的程序,用于客户端和服务端的数据交互。狭义上的Servlet程序是指用Java语言实现的,广义上的Servlet程序是指用任何语言实现的。
本文主要是学习狭义上的Servlet,即:Servlet(Server Applet),它是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
未经特别指明,后文提到的Servlet都是指Java Servlet
Servlet基础概念
- Servlet 接口提供了五个方法,其中三个生命周期方法和两个普通方法
- Servlet 的运行需要依赖Web服务器,通常使用的Web服务器是Tomcat,所以Tomcat也称Servlet容器
1.2 Servlet快速入门
任务:编写一个Servlet程序,并将其部署到Tomcat上,然后通过浏览器进行访问
Step1:创建Web项目
Step2:导入依赖
编写Servlet程序一般都需要导入jar包:
javax.servlet-api
,它是Sun公司根据Servlet接口开发的一套半成品软件,使用它我们只需要完成一部分事情就可以了,这样能大大减小开发Servlet的时间和难度?这次Sun公司没有像JDBC一样丢给第三方公司去实现了*^____^*
编写pom.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!--项目坐标--> <artifactId>day7_servlet</artifactId> <groupId>com.hhxy</groupId> <version>1.0-SNAPSHOT</version> <modelVersion>4.0.0</modelVersion> <packaging>war</packaging> <!--项目所依赖的JDK版本--> <properties> <maven.compiler.source>16</maven.compiler.source> <maven.compiler.target>16</maven.compiler.target> </properties> <!--导入项目的依赖--> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <!-- 此处为什么需要添加该标签? provided指的是在编译和测试过程中有效,最后生成的war包时不会加入 因为Tomcat的lib目录中已经有servlet-api这个jar包,如果在生成war包的时候生效就会和Tomcat中的jar包冲突,导致报错 --> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!--Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <!-- <path>/</path>--> </configuration> </plugin> </plugins> </build> </project>
Step3:编写Serlvet
实现 S e r v l e t 接口 → 重写接口方法 → 设置访问路径 实现Servlet接口\rightarrow{重写接口方法}\rightarrow{设置访问路径}实现Servlet接口→重写接口方法→设置访问路径
package com.hhxy.servlet; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; @WebServlet("/demo1")//使用注解设置ServletTest的访问路径,必须步骤 public class ServletTest implements Servlet { /** * 初识化方法 */ @Override public void init(ServletConfig servletConfig) throws ServletException { } /** * 获取Servlet配置文件信息的方法 */ @Override public ServletConfig getServletConfig() { return null; } /** * 服务方法 * ServletTest被访问,Tomcat就会自动执行service方法 */ @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("Hello Servlet<^_^>"); } /** * 获取Servlet信息的方法 */ @Override public String getServletInfo() { return null; } /** * 销毁方法 */ @Override public void destroy() { } }
Step4:测试
使用
Tomcat Maven
+Maven Helper
两个插件部署并运行Servlet程序:部署并运行成功后:
成功部署到Tomcat上后:
部署成功后,即可使用浏览器访问(每按一次回车就会被访问一次):
浏览器访问后控制台输出:
1.3 Servlet的执行流程和生命周期
1.3.1 执行流程
当Servlet程序被客户端访问时:
访问顺序:W e b 服务器 → W e b 项目 → 资源 Web服务器\rightarrow{Web项目}\rightarrow{资源}Web服务器→Web项目→资源
当访问资源时:Web服务器会自动为资源创建一个对象,然后自动调用对象中的
service
方法对请求进行处理,然后返回响应数据
1.3.2 生命周期及其接口方法
如果我们想更进一步了解Servlet的执行过程,就需要先了解Tomcat在什么时候为Servlet创建对象,什么时候调用service方法,什么时候返回响应数据,而了解这些就需要先了解Servlet的生命周期。
Servlet运行在Servlet容器(web服务器)中,其生命周期由容器来管理,分为4个阶段:
加载和实例化阶段:默认情况下,在Servlet第一次被访问时被加载,同时Tomcat创建Servlet对象
可以使用
loadOnStartup
属性改变Servlet对象的创建时间,示例:当loadOnStartup取负整数时,是默认情况,第一次访问创建Servlet对象;
当loadOnStartup取正整数时,Web服务器启动时就创建Servlet对象(取值越小优先级越高)
初始化阶段:在Servlet实例化之后,Tomcat将调用Servlet的
init()
方法初始化这个对象,完成一些如加载配置文件、创建连接等初始化的工作(init()
方法只调用一次)请求处理阶段:每次请求访问Servlet时,Tomcat都会调用
service()
方法对请求进行处理服务终止阶段:当需要释放内存或者Tomcat正常关闭时,Tomcat就会调用Servlet实例的
destroy()
方法完成资源的释放。在destroy()方法调用之后,容器会释放这个Servlet实例,该实例随后会被JVM垃圾回收器回收(destroy()
方法只调用一次)
init
:初始化方法,在Servlet被创建时执行,只执行一次void init(ServletConfig config)
service
:提供服务方法, 每次Servlet被访问,都会调用该方法void service(ServletRequest req, ServletResponse res)
备注:当我们在使用浏览器访问Servlet时,输入url后每按一次回车都会执行该方法一次
destroy
:销毁方法,当Servlet需要被释放内存时或者Web服务器正常关闭时,自动调用该方法销毁Servlet实例,只执行一次void destroy()
getServletInfo
获取Servlet相关信息的方法String getServletInfo() //该方法用来返回Servlet的相关信息,比如:作者、版权等
备注:该方法没有什么太大的用处,一般我们返回一个空字符串或者直接返回一个null即可
getServletConfig
:获取Servlet配置对象ServletConfigServletConfig getServletConfig()
当Tomcat初始化一个 Servlet 时,会自动创建一个ServletConfig对象,将该Servlet 的配置信息,封装到ServletConfig 对象中,而我们有时需要通过ServletConfig对象读取节点中的配置信息。但是我们应该怎么获得这个对象呢?一个方法中的需要使用另一个方法中的局部变量的解决方法:作用域提升
private ServletConfig servletConfig; public void init(ServletConfig config) throws ServletException { this.servletConfig = config;//将局部变量的值传递给成员变量 System.out.println("init..."); } public ServletConfig getServletConfig() { return servletConfig; }
1.4 Servlet体系结构
前面我们在实现Servlet实现类时,必须要重写五个方法,而且由于POST提交方式和GET提交方式请求参数的位置不同,这就需要我们每次在编写service方法时都需要进行判断,然后分别编写两种方式的处理请求参数的代码,这就会导致代码很冗余,所以我们就封装一个HttpServlet的类将这些重复代码进行封装,每次只需继承该类就可以不用写重复的代码了(程序员要学会偷懒?,避免重复工作,提高自己的工作效率,所以有机会还是得学习一下Python)
简而言之:GenericServlet
和HttpServlet
实现类是Java官方为我们编写好的,它们封装重复代码,能够有效提高Java程序员的开发效率
HttpServlet方法介绍
1)
doGet
:处理Get请求@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doGet(req, resp); }
2)
doPost
:处理Post请求@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); }
原始继承Servlet接口的写法:
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest)req; //1. 获取请求方式 String method = request.getMethod(); //2. 判断 if("GET".equals(method)){ // get方式的处理逻辑 doGet(req,res); }else if("POST".equals(method)){ // post方式的处理逻辑 doPost(req,res); } } protected void doPost(ServletRequest req, ServletResponse res) { } protected void doGet(ServletRequest req, ServletResponse res) { }
其实继承HttpServlet类后还能进一步进行简化,将doGet和doPost方法的代码进行合并,详情可以参观:详解Request和Response
1.5 Servlet访问路径的配置
1.5.1 使用urlPattern配置
urlPattern总共有4种配置方式,分别是:精确匹配、目录匹配、扩展名匹配、任意匹配
配置方式的优先级:
精确匹配 > 目录匹配 > 扩展名匹配 > /* > /
精确匹配:
目录匹配:
只要有
/user
,后面接/啥
都可以,当然也可以为空,直接使用localhost:8080/web-demo/user
也能成功访问扩展名匹配:
只要访问路径以
.do
结尾就可以,*
可以为空,比如直接以localhost:8080/web-demo/.do
任意匹配:
使用
/*
,就可以直接通过项目名localhost:8080/web-demo
进行访问了,后面也可以随便加/a/b/c...
也能成功访问(这就导致每次访问其他Servlet的同时也会访问使用了任意匹配的Serlvet)
当然
/
和/*
是一样的效果,只是优先级不一样。此外/
还有一个效果:当我们的项目中的Servlet配置了 “/”,会覆盖掉tomcat中的DefaultServlet,当其他的url-pattern都匹配不上时都会走这个ServletDefaultServlet
是用来处理静态资源,如果配置了"/"会把默认的覆盖掉,就会引发请求静态资源的时候没有走默认的而是走了自定义的Servlet类,最终导致静态资源不能被访问DefaultServlet被覆盖后,不能直接通过
/
1)
DefaultServlet
没有被覆盖,能够直接通过/静态资源名称
访问对应静态资源:2)
DefaultServlet
被覆盖,不会去访问静态资源,而是直接访问HttpServletTest
拓展:
urlPattern
可以同时配置多个访问路径示例:
package com.hhxy.servlet; 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(urlPatterns = {"/demo2","/demo3"}) //浏览器既可以通过/demo2又可以通过/demo3访问到HttpServletTest public class HttpServletTest extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doGet方法被调用了");//直接使用浏览器访问,是get访问 } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doPost方法被调用了"); } }
1.5.2 使用xml配置
Servlet3.0以前都是使用xml进行项目访问路径配置的,3.0及其以后就开始使用注解进行配置了。现在大部分企业也都是使用注解进行配置的,但是xml配置也需要看得懂<(^-^)>,相对注解配置而言,xml配置显得很繁琐多了?
示例:
目录:

XmlServletTest:
package com.hhxy.servlet;
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;
public class HttpServletTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet方法被调用了");//直接使用浏览器访问,是get访问
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost方法被调用了");
}
}
xml配置文件:
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!--1、给Servlet起别名-->
<servlet>
<servlet-name>demo3</servlet-name><!--Servlet的别名-->
<servlet-class>com.hhxy.servlet.XmlServletTest</servlet-class><!--Serlvet的全类名-->
</servlet>
<!--2、配置Serlvet访问路径-->
<servlet-mapping>
<servlet-name>demo3</servlet-name>
<url-pattern>/demo3</url-pattern><!--这里斜杠后面的访问路径不一定要和Servlet的别名一致-->
<!--这里可以使用前面urlPattern中的那四种路径访问方式-->
</servlet-mapping>
</web-app>
测试:
2、Filter
2.1 Filter概述
什么是Filter?
Filter本质是Java官方提供的一个接口(规范),目的就是为了规范我们开发Filter程序,但是一般我们说的Filter都是指实现这个接口的程序(也就是封装好的Filter接口实现类),我们将其称之为Filter(过滤器),它主要用来拦截客户端的请求数据,并对请求数据进行筛选、过滤,比如完成一些通用的操作,比如:判断登录是否成功、统一编码、权限控制、敏感字符处理。
2.2 Filter快速入门
任务:掌握Filter的基本使用,拦截请求并放行
Step1:创建Web项目,目录结构如下:
Step2:导入依赖
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.hhxy</groupId> <artifactId>day11_filter</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>16</maven.compiler.source> <maven.compiler.target>16</maven.compiler.target> </properties> <dependencies> <dependency> <!--servlet--> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--jsp--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!--tomcat7--> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> </configuration> </plugin> </plugins> </build> </project>
Step3:编写Filter
实现 j a v a x . s e r v l e t . F i l t e r 接口 → 重写接口方法 → 设置拦截路径 实现javax.servlet.Filter接口\rightarrow{重写接口方法}\rightarrow{设置拦截路径}实现javax.servlet.Filter接口→重写接口方法→设置拦截路径
package com.hhxy.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter("/*") //拦截所有请求 public class FilterDemo1 implements Filter { /** * 初识化方法 */ @Override public void init(FilterConfig filterConfig) throws ServletException { } /** * 过滤方法 */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("Hello Filter~~"); //放行 filterChain.doFilter(servletRequest,servletResponse); //如果不放行,浏览器将无法访问到hello.jsp } /** * 销毁方法 */ @Override public void destroy() { } }
Step4:测试
不放行:
放行:
2.3 Filter的执行流程
流程介绍:
- Step0:请求访问。浏览器请求访问hello.jsp,由于Filter的拦截,直接就跳转到Filter中
- Step1:拦截请求,执行放行前逻辑。Filter执行完放行前的逻辑,然后遇到放行方法,就放行了,直接跳转到hello.jsp
- Step2:响应请求。跳转到hello.jsp后,执行完hello.jsp后,再次回到Filter中的放行方法处
- Step3:执行放行后逻辑。回到放行后处,就执行Filter中放行后的逻辑
注意事项:放行前,只有Request对象中有数据,放行后Response对象中才有数据
示例:
拓展:过滤器链
过滤器链就是当我们使用浏览器访问一个资源时,中间被多个(至少两个)Filter进行了拦截,这多个过滤器就组成了过滤器链。
例如,以下的Filter1和Filter2就形成了过滤器链:
- 当我们取访问资源A时,资源A被Filter1拦截了,执行完Filter1的放行前逻辑后被放行来到资源A;
- 而资源A又被Filter2给拦截了,此时执行完Filter2的的放行前逻辑后就被放行到资源A;
- 当我们访问完资源A后,就来到Filter2的放行后逻辑
- 执行完后又来到Filter1的放行后逻辑,并最终将数据响应给浏览器
以上过程,就形成了一个过滤器链!示意图如下:
注意:Filter1和Filter2的执行顺寻是由他们的类名决定的,Tomcat内部会自动对Filter1和Filter2的类名进行一个一个的字母比较,直到判断有一个字母是排在前面就立马执行(判断规则是按照A → B → C → . . . A\rightarrow{B}\rightarrow{C}\rightarrow{...}A→B→C→...以及1、2、3……的先后顺序,大小写等价)
例如:
- Filter1的类名是Filter3,Filter2的类名是Filter4,则Tomcat先执行Filter3
- Filter1的类名是Filtera,FIlter2的类名是FilterB,则Tomcat先执行Filtera
2.4 拦截路径的配置
拦截路径表示 Filter 会对请求的哪些资源进行拦截,使用
@WebFilter
注解进行配置。如:@WebFilter("拦截路径")
具体配置和Servlet访问路径的配置相似?
拦截路径有如下四种配置方式:
拦截具体的资源:
/index.jsp
:只有访问index.jsp时才会被拦截目录拦截:
/user/*
:访问/user下的所有资源,都会被拦截后缀名拦截:
*.jsp
:访问后缀名为jsp的资源,都会被拦截拦截所有:
/*
:访问所有资源,都会被拦截
3、Listener
3.1 Listener概述
什么是Listener?
Listener本质是Java官方提供的一个接口(规范),目的就是为了规范我们开发Listener程序,而一般我们讲的都是指实现类Listener接口的程序(即封装好的Listener实现类),我们称之为LIstener(监听器),它主要用来监听
Application
、Session
、Request
三个对象的创建、销毁并对对象的属性进行增、删、改。关于三个对象的详情推荐阅读:Java中四大域对象
温馨提示:Listener(监听器)在现在的企业中已经用的很少了,因为在主流的Spring框架中,Listener已经帮我们写好了
Listener的分类
Listener主要分为三类八种:
备注:这里只有ServletContextListener
这个监听器比较常见,用来监听ServletContext
对象,详情
3.2 Listener快速入门
任务:
Step1:创建Web项目
项目目录如下:
Step2:导入依赖
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <artifactId>day7_servlet</artifactId> <groupId>com.hhxy</groupId> <version>1.0-SNAPSHOT</version> <modelVersion>4.0.0</modelVersion> <packaging>war</packaging> <properties> <maven.compiler.source>16</maven.compiler.source> <maven.compiler.target>16</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!--Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <!-- <path>/</path>--> </configuration> </plugin> </plugins> </build> </project>
Step3:编写Listener
实现 S e r v l e t C o n t e x t L i s t e n e r 接口 → 重写接口方法 → 设置注解 实现ServletContextListener接口\rightarrow{重写接口方法}\rightarrow{设置注解}实现ServletContextListener接口→重写接口方法→设置注解
package com.hhxy.Listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; @WebListener public class ContexLoaderListener implements ServletContextListener { /** * 初识化方法 * @param servletContextEvent */ @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("监听器已被启动"); } /** * 销毁方法 * @param servletContextEvent */ @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { } }
Step4:测试
总结
推荐阅读:
- IDEA中如何自定义Servlet模板【保姆级教程】:该文手把手教你如何配置一个专属你的Servlt、Filter、Listener模板
实战演练
任务:使用
Servlet
+JSP
+Filter
,实现登录注册,对表进行增、删、改、查案例所用到的东西:
- 使用到的架构模式:MVC+三层架构(简易版)
- 使用到的框架:MyBatis
- 使用到的设计模式:单例模式、代理模式、工厂模式
- 使用到的知识:后端(JDBC、Servlet、JSP、FIlter、Cookie、Session、HTTP、MySQL),前端(html、css、js)
- 使用到的jar包:mysql、mybatis、servlet、jsp、jstl
- 使用到的插件:Maven Helper、MyBatisX、Tomcat7
- 使用到的软件:IDEA、Maven、Tomcat、谷歌浏览器
- 实现的功能:
- 注册登录(防止SQL注入)
- 对数据库中表中的数据进行增删改查
- 访问拦截,无法直接越过登录访问到jsp
- 记住密码功能,登录一次后自动填充密码
- 数据回显
- 验证码
- 动态显示数据
该案例已上传到我的Gitee和Github上,感兴趣的可以去pull下来玩一玩?
目录结构:
界面展示: