JavaWeb三大组件分别是:Servlet、Filter、Listener
- 它们都是都是JavaEE的接口(规范),同时也是是一种技术,只是后两个不属于JavaEE的核心技术1
- 一般而言我们讲的三大组件都是指部署在Web服务器上实现这三个接口的服务端程序,主要作用就是让Web服务器能够更好地处理来自浏览器发送的请求数据
- Servlet主要用于响应浏览器发送的请求数据
- Filter主要用于对浏览器发送给Servlet的请求数据进行过滤
- Listener主要用于监听域对象的行为
什么是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程序,并将其部署到Tomcat上,然后通过浏览器进行访问
Step1:创建Web项目
Step2:导入依赖
编写Servlet程序一般都需要导入jar包:
javax.servlet-api
,它是Sun公司根据Servlet接口开发的一套半成品软件,使用它我们只需要完成一部分事情就可以了,这样能大大减小开发Servlet的时间和难度这次Sun公司没有像JDBC一样丢给第三方公司去实现了*^____^*
编写pom.xml文件:
<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_servletartifactId>
<groupId>com.hhxygroupId>
<version>1.0-SNAPSHOTversion>
<modelVersion>4.0.0modelVersion>
<packaging>warpackaging>
<properties>
<maven.compiler.source>16maven.compiler.source>
<maven.compiler.target>16maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
<configuration>
<port>8080port>
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上后:
当Servlet程序被客户端访问时:
访问顺序: W e b 服务器 → W e b 项目 → 资源 Web服务器\rightarrow{Web项目}\rightarrow{资源} Web服务器→Web项目→资源
当访问资源时:Web服务器会自动为资源创建一个对象,然后自动调用对象中的service
方法对请求进行处理,然后返回响应数据
如果我们想更进一步了解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配置对象ServletConfig
ServletConfig 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; }
推荐阅读:深度好文之Servlet技术详解(六)ServletContext对象&ServletConfig对象
前面我们在实现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
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都匹配不上时都会走这个Servlet
DefaultServlet
是用来处理静态资源,如果配置了"/"会把默认的覆盖掉,就会引发请求静态资源的时候没有走默认的而是走了自定义的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方法被调用了"); } }
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:
<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">
<servlet>
<servlet-name>demo3servlet-name>
<servlet-class>com.hhxy.servlet.XmlServletTestservlet-class>
servlet>
<servlet-mapping>
<servlet-name>demo3servlet-name>
<url-pattern>/demo3url-pattern>
servlet-mapping>
web-app>
测试:
什么是Filter?
Filter本质是Java官方提供的一个接口(规范),目的就是为了规范我们开发Filter程序,但是一般我们说的Filter都是指实现这个接口的程序(也就是封装好的Filter接口实现类),我们将其称之为Filter(过滤器),它主要用来拦截客户端的请求数据,并对请求数据进行筛选、过滤,比如完成一些通用的操作,比如:判断登录是否成功、统一编码、权限控制、敏感字符处理。
任务:掌握Filter的基本使用,拦截请求并放行
Step1:创建Web项目,目录结构如下:
Step2:导入依赖
pom.xml:
<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.0modelVersion>
<groupId>com.hhxygroupId>
<artifactId>day11_filterartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<maven.compiler.source>16maven.compiler.source>
<maven.compiler.target>16maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
<configuration>
<port>8080port>
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:测试
不放行:
放行:
流程介绍:
注意事项:放行前,只有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
拦截路径表示 Filter 会对请求的哪些资源进行拦截,使用
@WebFilter
注解进行配置。如:@WebFilter("拦截路径")
具体配置和Servlet访问路径的配置相似
拦截路径有如下四种配置方式:
拦截具体的资源:
/index.jsp
:只有访问index.jsp时才会被拦截
目录拦截:
/user/*
:访问/user下的所有资源,都会被拦截
后缀名拦截:
*.jsp
:访问后缀名为jsp的资源,都会被拦截
拦截所有:
/*
:访问所有资源,都会被拦截
什么是Listener?
Listener本质是Java官方提供的一个接口(规范),目的就是为了规范我们开发Listener程序,而一般我们讲的都是指实现类Listener接口的程序(即封装好的Listener实现类),我们称之为LIstener(监听器),它主要用来监听
Application
、Session
、Request
三个对象的创建、销毁并对对象的属性进行增、删、改。关于三个对象的详情推荐阅读:Java中四大域对象
温馨提示:Listener(监听器)在现在的企业中已经用的很少了,因为在主流的Spring框架中,Listener已经帮我们写好了
备注:这里只有ServletContextListener
这个监听器比较常见,用来监听ServletContext
对象,详情
任务:
Step1:创建Web项目
项目目录如下:
Step2:导入依赖
pom.xml:
<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_servletartifactId>
<groupId>com.hhxygroupId>
<version>1.0-SNAPSHOTversion>
<modelVersion>4.0.0modelVersion>
<packaging>warpackaging>
<properties>
<maven.compiler.source>16maven.compiler.source>
<maven.compiler.target>16maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
<configuration>
<port>8080port>
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下来玩一玩
- 知识汲取者的Gittee小仓库:传送门
- 知识汲取者的Github小仓库:传送门
目录结构:
界面展示:
JavaEE(Java Enterprise Edition,Java企业版)指Java企业级开发的技术规范总和。包含13项核心技术规范:JDBC、JNDI、EJB、RMI、JSP、Servlet、XML、JMS、Java IDL、JTS、JTA、JavaMail、JAF ↩︎ ↩︎