1. 官方文档
官方文档地址:Overview (Servlet 4.0 API Documentation - Apache Tomcat 9.0.83)
servlet 与 Tomcat 的关系:Tomcat 支持 Servlet
Tomcat 是一个开源的 Java 服务器,它主要用来提供 Web 服务,包括 HTTP 请求和响应的处理。Servlet 是 Java 的一种技术,用于创建动态 Web 应用程序。
Tomcat 支持 Servlet,这意味着你可以在 Tomcat 服务器上运行 Servlet 程序。Tomcat 为 Servlet 提供了一个运行环境,使得你可以使用 Servlet 技术来开发并部署 Web 应用程序。
简单来说,如果你想使用 Servlet 技术来开发 Web 应用程序,你需要一个支持 Servlet 的服务器,而 Tomcat 就是一个很好的选择。
2. Servlet概述
Servlet 是 Java 的一种技术,就是用Java编写的,本质就是Java类,用于创建动态 Web 应用程序。它是
一个运行在服务器端的 Java 小程序,可以响应客户端的请求,处理数据,并返回响应结果。Servlet 由
Sun Microsystems 公司提供一套规范,定义了动态资源如何在 Web 服务器上运行。
从代码层面上讲,Servlet 是一个接口,这意味着它定义了一组方法,这些方法可以由 Web 服务器调用。
在 Tomcat 中,Servlet 运行在一个称为“容器”的环境中。Tomcat 为 Servlet 提供了一个运行环境,这
个容器负责加载和运行 Servlet。Tomcat 会将来自客户端的 HTTP 请求转发给 Servlet 处理,并将
Servlet 的响应返回给客户端。
因此,Servlet 和 Tomcat 是相互依存的。如果你想使用 Servlet 技术来开发 Web 应用程序,你需要一个
支持 Servlet 的服务器,而 Tomcat 就是一个很好的选择。
简单总结就是:
Servlet是一种用于接收、处理客户端请求、响应给浏览器的动态资源的Java类。它必须满足特定的接口规范,并需要被部署在支持Servlet的Web服务器或应用服务器上才能正常运行。
3. Servlet基本使用
需求:
开发一个 HelloServlet
当浏览器 访问 http://localhost:8080/web 应用名/helloServlet 时,后台输出 "Hi HelloServelt"
具体步骤:
- 用IDEA创建一个项目,配置好Tomcat服务器
- 添加servlet-api.jar(在tomcat/lib下) 到工程, 因为servlet.jar 不是jdk自带的, 要引入
这里用两种方法:一个是自己导入实体Tomcatlib文件夹下的servlet的jar包
二是在pom文件配置联网下载Servlet的jar包
- 创建HelloServlet.java类,并实现Servlet接口
package com.example;import javax.servlet.*;//创建一个Servlet类,要实现Servlet接口
//实现接口的5个方法,但常用的是3个public class HelloServlet implements Servlet {/** 该方法常用* init初始化方法,在服务器启动时调用该方法* 该方法只执行一次* */@Overridepublic void init(ServletConfig config) throws ServletException {System.out.println("init方法被调用~");}/** getServletConfig方法* 返回ServletConfig 也就是返回ServLet的配置* */@Overridepublic ServletConfig getServletConfig() {return null;}/** 该方法使用的非常多* service方法,在服务器接收到请求时(含get/post方法)调用该方法* 该方法每次请求都会被调用* 该方法会把http请求转为Java对象,进行一系列操作* 处理请求之后会把Java对象转为http响应,返回给客户端* */@Overridepublic void service(ServletRequest req, ServletResponse res) {System.out.println("Hello Servlet!");}/** getServletInfo方法* 返回Servlet的描述信息*/@Overridepublic String getServletInfo() {return null;}/** 该方法常用* destroy销毁方法,* 在服务器关闭时调用该方法* 该方法只执行一次* */@Overridepublic void destroy() {}
}
- init(ServletConfig config): 这个方法在Servlet创建后立即被调用,一般用于初始化Servlet。它只会被调用一次。你可以在这里进行一些只需要在Servlet创建时执行一次的代码,例如加载一些配置信息。
- getServletConfig(): 这个方法返回一个ServletConfig对象,该对象包含了Servlet的配置信息。通常,你会在init(ServletConfig config)方法中获取这些配置信息,并在需要的时候使用。
- service(ServletRequest req, ServletResponse res): 这个方法是最重要的,它处理所有的HTTP请求。当服务器收到一个新的HTTP请求时,就会调用这个方法。这个方法会接收一个ServletRequest对象和一个ServletResponse对象作为参数。ServletRequest对象包含了客户端发送的请求信息,而ServletResponse对象则用于向客户端发送响应。
- getServletInfo( ): 这个方法返回一个字符串,用于描述Servlet的信息。这个字符串可以包含任何你希望提供的信息,例如版本信息、版权信息等。
- destroy( ): 这个方法在服务器关闭时被调用,用于清理资源。它只会被调用一次。在这个方法中,你可以执行一些在服务器关闭时需要执行的代码,例如关闭数据库连接或者释放其他资源。
记住,虽然这五个方法都是可选的,但init()、service()和destroy()是最常用的
- 在web.xml文件下配置HelloServlet的映射
为什么要怎么做,不进行这步,刚才写的Servlet是没办法调用实现功能的。
因为Servlet容器不知道如何将客户端的请求分发到该Servlet,因此无法将其用于处理客户端的请求。
<?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"><!--servlet-name 是servlet的名称,HelloServlet是servlet的类名--><!--servlet-class 是servlet的全路径--><!--servlet-mapping 是servlet的映射路径--><!--url-patter 是servlet的访问路径--><!--这样就可以访问/hello--><servlet><servlet-name>HelloServlet</servlet-name><servlet-class>com.example.HelloServlet</servlet-class></servlet><servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello</url-pattern></servlet-mapping></web-app>
- <servlet-name>:这是servlet的名称,通常用于标识servlet。在这里,servlet的名称是HelloServlet。
- <servlet-class>:这是servlet的全路径,也就是servlet类的完整类名。在这里,servlet的类名是com.example.HelloServlet。
- <servlet-mapping>:这个元素用于将servlet映射到URL模式。这意味着当应用程序接收到与该URL模式匹配的请求时,会调用相应的servlet。
- <servlet-name>:在<servlet-mapping>元素中,我们需要指定与<servlet>元素中相同的servlet名称。这样,服务器就知道哪个URL模式应该与哪个servlet关联。
- <url-pattern>:这是URL模式,指定了可以通过哪些URL访问该servlet。在这里,URL模式是/hello,这意味着可以通过在浏览器中输入http://localhost:8080/appName/hello(其中appName是应用程序的名称)来访问该servlet。
- 运行启动Tomcat服务器
在浏览器输入对应的地址并回车
IDEA控制台显示刚才在Servlet方法中的输出信息
如果此时多次刷新该页面,控制台会多次输出 “Hello Servlet”
3.1. 浏览器调用Servlet的流程
第一次HTTP请求:(也就是在浏览器地址栏输入回车对应的地址)
- Tomcat接收到HTTP请求后,会根据请求的URL路径在web.xml中进行匹配,找到对应的URL Pattern。
先在web.xml文件上找url-pattern是否有对应的,也就是“/hello”。如果有就会得到对应的servlet-name:HelloServlet。
同时,Tomcat维护了一个很大的HashMap<id,servlet>,查询HashMap中有没有这个servlet实例。根据servlet-name:HelloServlet去查询对应的id。
查询有这个servlet-name:HelloServlet的话,就会根据相应的servlet-class找到该类的全路径,找这个类在这个项目的哪里。
最后使用反射技术,将servlet实例化 -> init( )
并放到Tomcat维护的HashMap<id,Servlet>中去
- Tomcat会调用Servlet类的service()方法来处理HTTP请求。
在service()方法中,可以根据请求的类型(GET、POST等)和URL路径来确定 具体要执行的方法。
- 执行完service()方法后,Tomcat会返回响应给客户端。
- Tomcat会根据需要销毁或重新实例化Servlet类,以供下一次请求使用。
第二次及以后的相同HTTP请求,Tomcat会执行以下步骤:
- Tomcat接收到HTTP请求后,会根据请求的URL路径在web.xml中进行匹配,找到对应的Servlet类或URL Pattern。
- Tomcat会根据匹配结果直接调用已经实例化的Servlet类的service()方法来处理HTTP请求。
- 在service()方法中,可以根据请求的类型(GET、POST等)和URL路径来确定具体要执行的方法。
- 执行完service()方法后,Tomcat会返回响应给客户端。
对于第二次及以后的相同HTTP请求,Tomcat会有以下的不同:
- Tomcat会直接根据之前已经实例化的Servlet类来处理请求,而不需要再次实例化。
- Tomcat会直接调用已经初始化的Servlet类的service()方法来处理请求,而不需要再次调用init()方法进行初始化。
3.2. Servlet生命周期
- Servlet生命周期概述
Servlet的生命周期是指从创建Servlet对象到销毁Servlet对象的过程。这个过程包括三个阶段:初始化(init)、服务(service)和销毁(destroy)。
- 初始化阶段(init):当Servlet第一次被加载到内存时,Servlet容器会调用Servlet的init()方法进行初始化。init()方法在Servlet的整个生命周期中只会被调用一次。
- 服务阶段(service):当客户端发送请求时,Servlet容器会调用service()方法来处理客户端的请求。service()方法可以处理GET、POST等不同类型的请求。
- 销毁阶段(destroy):当Servlet不再需要时,Servlet容器会调用destroy()方法来销毁Servlet对象。在销毁阶段,Servlet对象将不再可用。
总之,Servlet的生命周期是指从创建Servlet对象到销毁Servlet对象的过程,包括初始化、服务和销毁三个阶段。
- Servlet容器
Servlet容器是一个运行环境,它负责创建Servlet对象,并调用Servlet的生命周期方法。Servlet容器负责管理Servlet的生命周期,包括初始化、服务和销毁阶段。
在Servlet的生命周期中,Servlet容器会调用Servlet的init()方法进行初始化,然后根据客户端的请求调用service()方法来处理请求。当Servlet不再需要时,Servlet容器会调用destroy()方法来销毁Servlet对象。
- Servlet主要的生命周期执行特点
生命周期 | 对应方法 | 执行时机 | 执行次数 |
构造对象 | 构造器 | 第一次请求或者容器启动 | 1 |
初始化 | init() | 构造完毕后 | 1 |
处理服务 | service(HttpServletRequest req,HttpServletResponse resp) | 每次请求 | 多次 |
销毁 | destory() | 容器关闭 | 1 |
简单讲,Servlet的生命周期就是从创建Servlet对象开始,经过初始化、处理服务,最后到销毁Servlet对象的过程。在这个过程中,开发人员可以关注和实现业务逻辑,而Servlet容器会负责调用相应的生命周期方法。
3.3. Get/Post请求的分发处理
当我们在开发Web应用程序时,通常需要处理两种主要的HTTP请求方法:Get和Post。
在Servlet开发中,我们通常会为这两种请求方法编写不同的处理逻辑。这是通过在Servlet中重写doGet和doPost方法来完成的。这两个方法是Java Servlet API定义的一部分,用于处理HTTP请求。
- doGet方法:当请求是通过GET方法发送时,Servlet容器会调用doGet方法。GET请求通常用于获取或查询资源,而不是发送数据。由于GET请求通常在URL中包含数据,因此这些数据可以在浏览器的地址栏中看到。因此,GET请求通常不适合发送敏感或大量数据。
- doPost方法:当请求是通过POST方法发送时,Servlet容器会调用doPost方法。POST请求通常用于发送数据,而不是获取资源。与GET请求不同,POST请求中的数据不会显示在URL中,因此更适合发送敏感或大量数据。
代码演示:
- 准备一个前端静态的注册页面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>注册</title>
</head>
<body><h1>用户注册</h1><form action="http://localhost:8080/_1_25_1_war_exploded/hello" method="post"><input type="text" name="username" placeholder="请输入用户名"><input type="submit" value="注册"></form>
</body>
</html>
- 后端Servlet写上相应的处理
后端的Servlet就用刚刚的HelloServlet,方便,web.xml也不用配置
注意:前端页面提交的数据是请求对象,但在service方法中的ServletRequest中并没有对应的方法去获取这个请求对象,怎么办,查看ServletRequest的子类是否有
但是ServletRequest类的实现类中的HttpServletRequest含有这个方法
显示下面这个界面是在IDEA中同时按下Ctrl+Alt再鼠标指向ServletRequest
该操作可以查看该接口的子接口和实现子类
所以就有了如下代码:
- 启动服务器,地址栏输入相关地址,并输入数据点击注册
- 结合上面Servlet中service写的方法,查看结果
控制台输出了这些
原因如下:
同理,如果前端中method的方法写成get,控制台也会有相应的输出
4. Servlet继承结构
下面两个是抽象类,上面仨是接口,具体源码可以自己在IDEA中Ctrl+鼠标键详情查看
这里稍微“简单”介绍一下:
Servlet接口
源码及功能解释
- 通过idea查看: 此处略
接口及方法说明
- Servlet 规范接口,所有的Servlet必须实现
-
- public void init(ServletConfig config) throws ServletException;
-
-
- 初始化方法,容器在构造servlet对象后,自动调用的方法,容器负责实例化一个ServletConfig对象,并在调用该方法时传入
- ServletConfig对象可以为Servlet 提供初始化参数
-
-
- public ServletConfig getServletConfig();
-
-
- 获取ServletConfig对象的方法,后续可以通过该对象获取Servlet初始化参数
-
-
- public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
-
-
- 处理请求并做出响应的服务方法,每次请求产生时由容器调用
- 容器创建一个ServletRequest对象和ServletResponse对象,容器在调用service方法时,传入这两个对象
-
-
- public String getServletInfo();
-
-
- 获取ServletInfo信息的方法
-
-
- public void destroy();
-
-
- Servlet实例在销毁之前调用的方法
-
GenericServlet 抽象类
源码
- 通过idea查看: 此处略
源码解释
- GenericServlet 抽象类是对Servlet接口一些固定功能的粗糙实现,以及对service方法的再次抽象声明,并定义了一些其他相关功能方法
-
- private transient ServletConfig config;
-
-
- 初始化配置对象作为属性
-
-
- public GenericServlet() { }
-
-
- 构造器,为了满足继承而准备
-
-
- public void destroy() { }
-
-
- 销毁方法的平庸实现
-
-
- public String getInitParameter(String name)
-
-
- 获取初始参数的快捷方法
-
-
- public Enumeration getInitParameterNames()
-
-
- 返回所有初始化参数名的方法
-
-
- public ServletConfig getServletConfig()
-
-
- 获取初始Servlet初始配置对象ServletConfig的方法
-
-
- public ServletContext getServletContext()
-
-
- 获取上下文对象ServletContext的方法
-
-
- public String getServletInfo()
-
-
- 获取Servlet信息的平庸实现
-
-
- public void init(ServletConfig config) throws ServletException()
-
-
- 初始化方法的实现,并在此调用了init的重载方法
-
-
- public void init() throws ServletException
-
-
- 重载init方法,为了让我们自己定义初始化功能的方法
-
-
- public void log(String msg)
- public void log(String message, Throwable t)
-
-
- 打印日志的方法及重载
-
-
- public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
-
-
- 服务方法再次声明
-
-
- public String getServletName()
-
-
- 获取ServletName的方法
-
HttpServlet 抽象类
源码
- 通过idea查看: 此处略
解释
- abstract class HttpServlet extends GenericServlet HttpServlet抽象类,除了基本的实现以外,增加了更多的基础功能
-
- private static final String METHOD_DELETE = "DELETE";
- private static final String METHOD_HEAD = "HEAD";
- private static final String METHOD_GET = "GET";
- private static final String METHOD_OPTIONS = "OPTIONS";
- private static final String METHOD_POST = "POST";
- private static final String METHOD_PUT = "PUT";
- private static final String METHOD_TRACE = "TRACE";
-
-
- 上述属性用于定义常见请求方式名常量值
-
-
- public HttpServlet() {}
-
-
- 构造器,用于处理继承
-
-
- public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
-
-
- 对服务方法的实现
- 在该方法中,将请求和响应对象转换成对应HTTP协议的HttpServletRequest HttpServletResponse对象
- 调用重载的service方法
-
-
- public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
-
-
- 重载的service方法,被重写的service方法所调用
- 在该方法中,通过请求方式判断,调用具体的do***方法完成请求的处理
-
-
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
-
-
- 对应不同请求方式的处理方法
- 除了doOptions和doTrace方法,其他的do*** 方法都在故意响应错误信息
-
5. 继承HttpServlet开发Servlet
5.1. HttpServlet介绍
实际开发中,在Servlet的继承体系下,很少直接实现Servlet接口去写代码,更多的是使用HttpServlet
自己写一个自定义的Servlet接口去继承HttpServlet抽象类
5.2. 使用相关代码测试
HelloServlet
快捷生成doget、dopost的方法
右键选择生成或则Alt+insert键
找到重写方法
在选择对应的doget、dopost方法即可
对应的web.xml文件配置
register.html
注意,这里是post方法
启动服务器,并输入相关地址
5.3. HttpServletRequest
- HttpServletRequest概念
HttpServletRequest是Java Servlet API中的一个核心接口,它代表了来自客户端的HTTP请求。这个接口提供了许多方法,用于获取请求的各种属性和参数,如请求的URI、请求方法、请求头信息、请求参数等。
当一个HTTP请求到达Servlet容器(如Tomcat)时,容器会将请求报文转换成一个HttpServletRequest对象,并将这个对象作为参数传递给Servlet的service方法。这样,Servlet就可以通过HttpServletRequest对象获取到所有关于该请求的信息,从而进行处理。
- HttpServletRequest常见API
- 获取请求行信息相关(方式,请求的url,协议及版本)
API | 功能解释 |
StringBuffer getRequestURL(); | 获取客户端请求的url |
String getRequestURI(); | 获取客户端请求项目中的具体资源 |
int getServerPort(); | 获取客户端发送请求时的端口 |
int getLocalPort(); | 获取本应用在所在容器的端口 |
int getRemotePort(); | 获取客户端程序的端口 |
String getScheme(); | 获取请求协议 |
String getProtocol(); | 获取请求协议及版本号 |
String getMethod(); | 获取请求方式 |
- 获得请求头信息相关
API | 功能解释 |
String getHeader(String headerName); | 根据头名称获取请求头 |
Enumeration getHeaderNames(); | 获取所有的请求头名字 |
String getContentType(); | 获取content-type请求头 |
- 获得请求参数相关
API | 功能解释 |
String getParameter(String parameterName); | 根据请求参数名获取请求单个参数值 |
String[] getParameterValues(String parameterName); | 根据请求参数名获取请求多个参数值数组 |
Enumeration getParameterNames(); | 获取所有请求参数名 |
Map<String, String[]> getParameterMap(); | 获取所有请求参数的键值对集合 |
BufferedReader getReader() throws IOException; | 获取读取请求体的字符输入流 |
ServletInputStream getInputStream() throws IOException; | 获取读取请求体的字节输入流 |
int getContentLength(); | 获得请求体长度的字节数 |
- 其他API
API | 功能解释 |
String getServletPath(); | 获取请求的Servlet的映射路径 |
ServletContext getServletContext(); | 获取ServletContext对象 |
Cookie[] getCookies(); | 获取请求中的所有cookie |
HttpSession getSession(); | 获取Session对象 |
void setCharacterEncoding(String encoding) ; | 设置请求体字符集 |
5.4. HttpServletResponse
- HttpServletResponse概念
HttpServletResponse是Java Servlet API中的另一个核心接口,它代表了服务器对客户端的响应。这个接口提供了一些方法,用于设置响应头信息、输出响应内容、设置响应状态等。
当Servlet的service方法处理完请求后,它可以通过HttpServletResponse对象将响应内容写入到响应报文中,并将响应报文发送给客户端。通过HttpServletResponse对象,Servlet可以设置响应的状态码、响应头信息、响应内容等。
- HttpServletResponse常见API
- 设置响应行相关
API | 功能解释 |
void setStatus(int code); | 设置响应状态码 |
- 设置响应头相关
API | 功能解释 |
void setHeader(String headerName, String headerValue); | 设置/修改响应头键值对 |
void setContentType(String contentType); | 设置content-type响应头及响应字符集(设置MIME类型) |
- 设置响应体相关
API | 功能解释 |
PrintWriter getWriter() throws IOException; | 获得向响应体放入信息的字符输出流 |
ServletOutputStream getOutputStream() throws IOException; | 获得向响应体放入信息的字节输出流 |
void setContentLength(int length); | 设置响应体的字节长度,其实就是在设置content-length响应头 |
- 其他API
API | 功能解释 |
void sendError(int code, String message) throws IOException; | 向客户端响应错误信息的方法,需要指定响应码和响应信息 |
void addCookie(Cookie cookie); | 向响应体中增加cookie |
void setCharacterEncoding(String encoding); | 设置响应体字符集 |
MIME类型
- MIME类型,可以理解为文档类型,用户表示传递的数据是属于什么类型的文档
- 浏览器可以根据MIME类型决定该用什么样的方式解析接收到的响应体数据
- 可以这样理解: 前后端交互数据时,告诉对方发给对方的是 html/css/js/图片/声音/视频/... ...
- tomcat/conf/web.xml中配置了常见文件的拓展名和MIMIE类型的对应关系
- 常见的MIME类型举例如下
文件拓展名 | MIME类型 |
.html | text/html |
.css | text/css |
.js | application/javascript |
.png /.jpeg/.jpg/... ... | image/jpeg |
.mp3/.mpe/.mpeg/ ... ... | audio/mpeg |
.mp4 | video/mp4 |
.m1v/.m1v/.m2v/.mpe/... ... | video/mpeg |
6. Servlet注意事项
- Servlet 是一个特殊的 Java 类,用于在 Web 服务器或应用服务器上提供动态内容。它们不能独立运行,需要在一个 Servlet 容器(或称为 Servlet 引擎)中运行。
Servlet 容器提供了一个环境,让 Servlet 能够与 HTTP 请求和响应进行交互,并提供了诸如生命周期管理、安全性和并发处理等重要功能。
Servlet 实现了一个叫做 javax.servlet.Servlet 的接口,这个接口定义了一些方法,比如 init(), service(), doGet(), doPost(), 和 destroy()。这些方法使得 Servlet 能够处理 HTTP 请求,生成响应,以及在 Servlet 的生命周期中进行必要的操作。
为了运行 Servlet,你需要一个 Servlet 容器,比如 Tomcat 或者 Jetty。这些容器会加载 Servlet 类,管理它们的生命周期,并提供一个环境让它们能够与 HTTP 请求和响应进行交互。
- 对于每次请求,服务器通常只会创建一个Servlet实例,这个实例会一直存在直到Web应用程序被重新部署或服务器关闭。每个请求会得到一个新的对象实例来处理,但实例变量在每次请求后会被重置。当Web应用程序被重新部署或服务器重启时,所有的Servlet实例都会被销毁并重新创建,以确保正确运行。
- 在Servlet的生命周期中,init方法是只被调用一次的。这是因为Servlet的实例在服务器启动时就被创建,然后一直存在,直到Web应用程序被重新部署或服务器关闭。在Servlet的生命周期内,init方法只会在Servlet实例创建时被调用一次,用于初始化Servlet。
- 对于每次用户发出的请求,Servlet引擎都会调用一次Servlet的service方法。这个service方法会接收两个参数:HttpServletRequest请求对象和HttpServletResponse响应对象。这两个对象是Servlet引擎为每个请求创建的新的对象。
- 对于每次用户请求,Servlet引擎都会为每个请求创建一个新的HttpServletRequest对象和一个新的HttpServletResponse对象。这两个对象包含了请求和响应的所有信息。这些对象会被传递给service方法,service方法会根据请求的方式(如GET、POST等)来调用doXXX方法(如doGet、doPost等)来处理请求。
7. ServletConfig和ServletContext
7.1. ServletConfig的使用
ServletConfig是Java Servlet API中的一个接口,它提供了Servlet的初始化配置参数。每个Servlet实例都有一个自己独立且唯一的ServletConfig对象。
当Web应用程序被部署并启动时,Servlet容器会实例化每个Servlet,并为每个Servlet实例创建一个ServletConfig对象。这个ServletConfig对象包含了在Web应用程序的部署描述符(web.xml文件)中为该Servlet指定的初始化参数。
这些初始化参数可以在Servlet的初始化方法(init())中被访问和利用。在Servlet的生命周期中,ServletConfig对象作为属性被传递给Servlet的init方法。这样,Servlet就可以在初始化时获取到它所需要的配置信息,从而进行相应的初始化操作。
举个简单的例子就是:
ServletConfig可以类比为一家餐厅的菜单。当顾客进入餐厅时,他们会看到菜单,并根据菜单选择他们想吃的菜品。菜单提供了关于菜品的信息,如菜名、价格、食材等。同样地,ServletConfig提供了关于Servlet的信息,如Servlet的名称、初始化参数等。
在Web应用程序中,Servlet扮演着处理请求的角色,就像餐厅中的服务员一样。当一个请求到达Servlet时,Servlet会根据ServletConfig中的信息来处理请求。就像服务员根据菜单上的信息为顾客提供服务一样。
ServletConfig 类能干什么
- 获取 Servlet 程序的 servlet-name 的值:通过调用 getServletName() 方法,可以获取 Servlet 的名称。这个名称是在 web 应用程序的部署描述符(web.xml 文件)中定义的。
- 获取初始化参数 init-param:ServletConfig 接口提供了 getInitParameter 方法,用于获取在 web.xml 文件中为 Servlet 定义的初始化参数。这些参数可以在 Servlet 的生命周期中使用。
- 获取 ServletContext:通过调用 getServletContext 方法,可以获取与当前 Servlet 关联的 ServletContext 对象。ServletContext 是整个 web 应用程序共享的上下文,它包含了与该应用程序相关的数据和属性。
ServletConfig是一个接口,定义了如下API:
package jakarta.servlet;
import java.util.Enumeration;
public interface ServletConfig {String getServletName();ServletContext getServletContext();String getInitParameter(String var1);Enumeration<String> getInitParameterNames();
}
方法名 | 作用 |
getServletName() | 获取<servlet-name>HelloServlet</servlet-name>定义的Servlet名称 |
getServletContext() | 获取ServletContext对象 |
getInitParameter() | 获取配置Servlet时设置的『初始化参数』,根据名字获取值 |
getInitParameterNames() | 获取所有初始化参数名组成的Enumeration对象 |
ServletConfig怎么用,测试代码如下
- 定义Servlet
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletConfig servletConfig = this.getServletConfig();// 根据参数名获取单个参数String value = servletConfig.getInitParameter("param1");System.out.println("param1:"+value);// 获取所有参数名Enumeration<String> parameterNames = servletConfig.getInitParameterNames();// 迭代并获取参数名while (parameterNames.hasMoreElements()) {String paramaterName = parameterNames.nextElement();System.out.println(paramaterName+":"+servletConfig.getInitParameter(paramaterName));}}
}public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletConfig servletConfig = this.getServletConfig();// 根据参数名获取单个参数String value = servletConfig.getInitParameter("param1");System.out.println("param1:"+value);// 获取所有参数名Enumeration<String> parameterNames = servletConfig.getInitParameterNames();// 迭代并获取参数名while (parameterNames.hasMoreElements()) {String paramaterName = parameterNames.nextElement();System.out.println(paramaterName+":"+servletConfig.getInitParameter(paramaterName));}}
}
- 配置Servlet
<servlet><servlet-name>ServletA</servlet-name><servlet-class>com.atguigu.servlet.ServletA</servlet-class><!--配置ServletA的初始参数--><init-param><param-name>param1</param-name><param-value>value1</param-value></init-param><init-param><param-name>param2</param-name><param-value>value2</param-value></init-param></servlet><servlet><servlet-name>ServletB</servlet-name><servlet-class>com.atguigu.servlet.ServletB</servlet-class><!--配置ServletB的初始参数--><init-param><param-name>param3</param-name><param-value>value3</param-value></init-param><init-param><param-name>param4</param-name><param-value>value4</param-value></init-param></servlet><servlet-mapping><servlet-name>ServletA</servlet-name><url-pattern>/servletA</url-pattern></servlet-mapping><servlet-mapping><servlet-name>ServletB</servlet-name><url-pattern>/servletB</url-pattern></servlet-mapping>
7.2. ServletContext的使用
ServletContext是Java Servlet API中的一个接口,它代表了Web应用程序的上下文,也称为应用域对象。在Web应用程序中,每个应用程序都会有一个唯一的ServletContext对象。这个对象由Servlet容器在应用程序启动时创建,并在整个应用程序的生命周期内保持存在。
ServletContext对象是所有Servlet共享的,这意味着在同一个Web应用程序中,所有的Servlet都可以访问和修改同一个ServletContext对象。这为Servlet之间的数据共享和协作提供了方便的机制。
ServletContext可以为所有的Servlet提供初始配置参数。这些参数可以在Web应用程序的部署描述符(web.xml文件)中定义。当Web应用程序启动时,容器会将这些参数传递给每个Servlet,作为它们的初始化参数。这样,Servlet就可以在初始化时获取到它们所需要的配置信息。
简单来说,ServletContext就像是一个大的共享容器,它存储了Web应用程序的配置信息,并且可以被所有的Servlet访问和修改。
ServletContext怎么用
- 配置ServletContext参数
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"version="5.0"><context-param><param-name>paramA</param-name><param-value>valueA</param-value></context-param><context-param><param-name>paramB</param-name><param-value>valueB</param-value></context-param></web-app>
- 在Servlet中获取ServletContext并获取参数
package com.atguigu.servlet;import jakarta.servlet.ServletConfig;import jakarta.servlet.ServletContext;import jakarta.servlet.ServletException;import jakarta.servlet.http.HttpServlet;import jakarta.servlet.http.HttpServletRequest;import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Enumeration;public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 从ServletContext中获取为所有的Servlet准备的参数ServletContext servletContext = this.getServletContext();String valueA = servletContext.getInitParameter("paramA");System.out.println("paramA:"+valueA);// 获取所有参数名Enumeration<String> initParameterNames = servletContext.getInitParameterNames();// 迭代并获取参数名while (initParameterNames.hasMoreElements()) {String paramaterName = initParameterNames.nextElement();System.out.println(paramaterName+":"+servletContext.getInitParameter(paramaterName));}}}
8. Servlet注解方式
8.1. 定义
@WebServlet注解是Java Servlet API的一部分,用于在Java Servlet应用程序中定义Servlet。它允许开发人员将Servlet类映射到特定的URL路径或Servlet名称,以便处理来自客户端的请求。
通过使用@WebServlet注解,开发人员可以将Servlet类与特定的URL模式关联起来,以便当客户端发出请求时,Servlet可以拦截和处理这些请求。这个注解可以用于将Servlet映射到根路径或特定的子路径,以及指定Servlet的初始化参数和其他配置选项。
8.2. 代码演示
MyServlet.java
不在web.xml进行配置
前端测试代码,action设置为注解的urlPatterns
启动服务器
从上面也看出来了,@WebServlet注解确实可以简化Servlet的映射设置过程。通过使用@WebServlet注解,开发人员可以更快速地将Servlet类与特定的URL路径进行关联,而无需在Web.xml文件中手动配置。这有助于减少开发时间和代码复杂度,特别是在小型项目中。然而,需要注意的是,@WebServlet注解是Java Servlet API的一部分,需要在支持Servlet规范的容器中运行。
8.3. @WebServlet注解
annotation就是注解的意思
package javax.servlet.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {/*** The name of the servlet** @return the name of the servlet*/String name() default "";/*** The URL patterns of the servlet** @return the URL patterns of the servlet*/String[] value() default {};/*** The URL patterns of the servlet** @return the URL patterns of the servlet*/String[] urlPatterns() default {};/*** The load-on-startup order of the servlet ** @return the load-on-startup order of the servlet*/int loadOnStartup() default -1;/*** The init parameters of the servlet** @return the init parameters of the servlet*/WebInitParam [] initParams() default {};/*** Declares whether the servlet supports asynchronous operation mode.** @return {@code true} if the servlet supports asynchronous operation mode* @see javax.servlet.ServletRequest#startAsync* @see javax.servlet.ServletRequest#startAsync(ServletRequest,* ServletResponse)*/boolean asyncSupported() default false;/*** The small-icon of the servlet** @return the small-icon of the servlet*/String smallIcon() default "";/*** The large-icon of the servlet** @return the large-icon of the servlet*/String largeIcon() default "";/*** The description of the servlet** @return the description of the servlet*/String description() default "";/*** The display name of the servlet** @return the display name of the servlet*/String displayName() default "";}
上面是从IDEA上面扒下来的WebServlet.java的源码,简单概括就是
它是用来定义一个servlet的配置信息的:
name()
:返回servlet的名字,默认为空字符串。value()
和urlPatterns()
:这两个方法是等价的,都是用来设置URL模式的。当请求匹配这些模式时,该servlet将被调用。loadOnStartup()
:设置servlet在应用启动时加载的顺序。默认值为-1,表示容器可自由选择加载时机。initParams()
:设置servlet的初始化参数。asyncSupported()
:声明servlet是否支持异步操作模式。如果为true,那么servlet可以使用startAsync()
方法进行异步处理。smallIcon()
和largeIcon()
:分别设置servlet的小图标和大图标。默认都为空字符串。description()
:设置servlet的描述信息。默认为空字符串。displayName()
:设置servlet的显示名。默认为空字符串。
上面的例子就用到了name和urlPatterns,设定servlet的名字和它的URL地址
8.4. WebServlet注解原理
- 这是没有WebServlet注解的HTTP请求方式:
- Tomcat接收到HTTP请求后,会根据请求的URL路径在web.xml中进行匹配,找到对应的URL Pattern。
先在web.xml文件上找url-pattern是否有对应的,也就是“/hello”。如果有就会得到对应的servlet-name:HelloServlet。
同时,Tomcat维护了一个很大的HashMap<id,servlet>,查询HashMap中有没有这个servlet实例。根据servlet-name:HelloServlet去查询对应的id。
查询有这个servlet-name:HelloServlet的话,就会根据相应的servlet-class找到该类的全路径,找这个类在这个项目的哪里。
最后使用反射技术,将servlet实例化 -> init( )
并放到Tomcat维护的HashMap<id,Servlet>中去
- Tomcat会调用Servlet类的service()方法来处理HTTP请求。
在service()方法中,可以根据请求的类型(GET、POST等)和URL路径来确定 具体要执行的方法。
- 执行完service()方法后,Tomcat会返回响应给客户端。
- Tomcat会根据需要销毁或重新实例化Servlet类,以供下一次请求使用。
- 如果此时用了WebServlet注解,会有一些小变化:
当Tomcat找到匹配的URL Pattern时,它会查看Servlet类上是否有@WebServlet注解。注解中通常包含一个urlPatterns属性,该属性指定了该Servlet类应该映射到的URL路径。例如,@WebServlet(urlPatterns = "/hello")。
如果存在@WebServlet注解,Tomcat会根据注解中的urlPatterns属性将该Servlet类映射到相应的URL路径。然后,Tomcat会使用反射技术实例化该Servlet类,并调用它的init()方法进行初始化。
此时,web.xml文件不进行配置也是可以的
与之前不同的是,Tomcat不再维护一个HashMap<id, Servlet>来存储Servlet实例。相反,Tomcat使用注解的信息来动态地创建和销毁Servlet实例,以处理HTTP请求。这意味着每次请求都会创建一个新的Servlet实例(除非使用了持久化Servlet),而不是重用先前创建的实例。
总之,使用@WebServlet注解简化了Servlet的配置过程,并且允许动态地创建和销毁Servlet实例。然而,需要注意的是,使用注解可能会增加每次请求的处理开销,因为每次都需要动态地创建和销毁Servlet实例。在需要高性能或高并发的场景下,可能需要权衡使用注解和预创建Servlet实例的利弊。
9. 请求转发和响应重定位
9.1. 概述
请求转发和响应重定向是Web应用程序中常用的两种页面跳转方法。以下是关于这两种方法的详细解释:
请求转发(Request Forwarding):
请求转发是一种由Servlet实现的请求转发机制。当一个Servlet接收到一个HTTP请求后,它可以通过调用RequestDispatcher接口的forward()方法将请求转发给另一个Servlet或JSP页面。这个过程是服务器内部的操作,客户端并不知道。请求转发的优点是实现简单,性能较好。
举个例子,张三向李四借钱,但李四没有钱。于是李四向王五借钱,并告诉王五将钱借给张三。这个过程中,张三只向李四请求借钱,但实际上钱是从王五那里借来的。
响应重定向(Response Redirection):
响应重定向是另一种页面跳转方法,它通过在客户端进行操作来实现。当一个Servlet接收到一个HTTP请求后,它可以通过调用HttpServletResponse对象的sendRedirect()方法将客户端重定向到另一个页面。重定向是通过HTTP协议的3xx响应码实现的,客户端会收到一个新的URL,并重新向这个URL发送请求。
在举个例子,张三向李四借钱,但李四没有钱。李四告诉张三去找王五借钱。于是张三自己去找王五借钱,这个过程中,张三的请求被重定向到了王五那里。
总结一下,请求转发和响应重定向的区别:
- 请求转发是在服务器内部进行的操作,客户端并不知道;而响应重定向是客户端接收到一个新的URL,并重新向这个URL发送请求。
- 请求转发性能较好,因为只需要进行一次HTTP请求;而响应重定向需要重新发送请求,性能较差。
- 请求转发只能用于同一个Web应用程序内;而响应重定向可以用于不同的Web应用程序之间。
9.2. 请求转发
- 请求转发可以通过HttpServletRequest对象获取请求转发器实现。
- 请求转发是服务器内部的行为,对客户端是屏蔽的。
- 客户端只发送了一次请求,地址栏不变。
- 服务端只产生了一对请求和响应对象,这一对对象会继续传递给下一个资源。
- 请求参数和请求域中的数据都可以在请求转发中传递。
- 请求转发可以用于转发给其他Servlet动态资源、静态资源或受保护的资源。
- 请求转发不能用于转发到外部资源。
代码演示:
9.3. 响应重定向
- 响应重定向是通过HttpServletResponse对象的sendRedirect方法实现的。
- 响应重定向是服务端通过302响应码和路径告诉客户端自己去找其他资源,是由服务端提示下的客户端行为。
- 响应重定向至少需要客户端发送两次请求,且客户端地址栏会发生变化。
- 在响应重定向中,服务端会产生多对请求和响应对象,且请求和响应对象不会传递给下一个资源。
- 因为整个过程中产生了多个HttpServletRequset对象,所以请求参数无法在响应重定向中传递,请求域中的数据也无法传递。
- 响应重定向可以是其他Servlet动态资源,也可以是一些静态资源以实现页面跳转。
- 响应重定向无法转发到受保护的资源,如WEB-INF下的资源。
- 响应重定向可以转发到外部资源,即本项目以外的资源。
代码演示: