Java之Servlet学习笔记(更新中...)

Servlet是什么

Servlet是Server Applet的缩写,即“服务器端小程序”,是一种使用Java语言开发动态网站的技术。它可以接收客户端发送过来的请求,并响应数据给客户端。

Servlet具有以下特点:

1、Servlet提供了可被服务器动态加载并执行的程序代码,为来自客户端的请求提供服务;

2、Servlet完全使用Java语言编写,运行Servlet的服务器须支持Java语言;

3、Servlet是一种在服务器端运行的小程序,不依赖于浏览器,不管是浏览器是否支持Java语言,都能请求你方法服务器端的Servlet。

Servlet是一种规范

所有的 Servlet 功能都是通过一个名为 jakarta.servlet.Servlet 的接口(Interface)向外暴露的,该接口的源码如下:

public interface Servlet {
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}

可以看到,Servlet 接口仅提供了 5 个抽象方法,并未给出任何方法实现,这是因为 Servlet 其实只是一种 Java Web 开发的规范,或者说是一套 Java Web 开发的技术标准。仅仅有规范是无法做任何事的,必须要有人去实现这个 Servlet 接口并重写其中方法,实现 Servlet 规范提到的各种功能才行。

直接实现 Servlet 接口比较麻烦,需要实现多个方法,所以 Servlet 规范又提供了两个抽象类,分别是 GenericServlet 类和 HttpServlet 类,它们各自都实现了 Servlet 接口的很多常用功能。和 GenericServlet 类相比,HttpServlet 类更加方便,所以实际开发中一般都继承自 HttpServlet 类。

Servlet 规范是开放的,除了 Sun 公司之外,其它公司也可以实现 Servlet 规范,目前常见的实现了 Servlet 规范的产品包括 Tomcat、Weblogic、Jetty、Jboss、WebSphere 等,它们都被称为“Servlet 容器”。

Servlet容器

我们知道,Servlet 用于生成动态网页的,一个动态网页对应一个 Servlet。编写一个 Servlet,实际上就是按照 Servlet 规范编写一个 Java 类。

但 Servlet 类中是没有 main() 方法的,不能独立运行。它必须被部署到 Servlet 容器中,由容器来实例化和调用 Servlet 的方法。Servlet 容器可以在 Servlet 的生命周期内对 Servlet 进行保存和管理:

alt

从上图可知,Web 服务器是整个动态网站的“大门”,用户的 HTTP 请求首先到达 Web 服务器,Web 服务器会判断该请求是静态资源还是动态资源:如果是静态资源就直接返回,此时相当于用户下载了一个服务器上的文件;如果 Web 服务器接收到的是一个指向 Servlet 等动态资源的请求,那么 Web 服务器并不会把这个请求直接交给 Servlet 本身,而是转交给部署该 Servlet 的容器。

Servlet 容器接收到请求以后,会根据配置文件(web.xml)找到对应的 Servlet 类,将它加载并实例化,然后调用其中的方法来处理用户请求。处理结束后,Servlet 容器会将处理结果再转交给 Web 服务器,由 Web 服务器将处理结果进行封装,并以 HTTP 响应的形式发送给用户的浏览器进行展示。

Tomcat 是最常用、最流行的 Servelt 容器之一。

一般情况下,Servlet 容器具有如下功能

  • 容器提供了各种方法,使得 Servlet 可以实现与 Web 服务器对话。开发人员只需要专注于如何在 Servlet 中实现业务逻辑即可,至于 Servlet 与 Web 服务器对话的细节则不必理会。
  • 容器能够控制 Servlet 的生命周期。容器负责加载、实例化和初始化 Servlet、调用 Servlet 方法、销毁 Servlet 实例。
  • 容器支持多线程管理。容器接收 Servlet 请求时,容器自动为其创建新线程,运行完成时,容器结束线程。
  • 容器为 Servlet 的可移植性提供了可能。利用容器,可以使用 XML 部署描述文件来配置和修改安全性,不需将其编码写到 Servlet 类代码中。
  • 容器负责将一个 JSP 文件转译成一个 Servlet。

Servlet三种创建方式

我们在开发属于自己的 Servlet 类时,既可以直接实现 Servlet 接口,也可以通过继承 GenericServlet 抽象类或 HttpServlet 抽象类(HttpServlet是GenericServlet的子类)实现。

1、实现 Servlet 接口

我们可以通过编写一个 Java 类实现(implements)Servlet 接口,并重写 Servlet 接口中全部 5 个方法的方式来创建一个 Servlet 类

public class MyServlet implements Servlet {...}

2、继承 GenericServlet 抽象类

Servlet API 中还提供了一个名为 GenericServlet 的抽象类,与 Servlet 接口一样,GenericServlet 也位于 jakarta.servlet 包下。GenericServlet 实现了 Servlet 接口,并为除了 service() 方法外的其他四个方法,都提供了与任何网络协议都无关的通用实现,因此我们在通过继承 GenericServlet 创建 Servlet 时,只需要重写 service() 方法即可,大大减少了创建 Servlet 的工作量。

示例代码如下:

import jakarta.servlet.GenericServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author C语言中网 http://c.biancheng.net
* 继承 GenericServlet 接口,重写 service()方法,创建 Servlet
*/
public class MyGenericServlet extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //设置字符集
        servletResponse.setContentType("text/html;charset=UTF-8");
        //使用PrintWriter.write()方法向前台页面输出内容
        PrintWriter writer = servletResponse.getWriter();
        writer.write("C语言中文网:http://c.biancheng.net");
        writer.close();
    }
}

3、继承 HttpServlet 抽象类

HttpServlet 类位于 jakarta.servlet.http 包下,它是 GenericServlet 抽象类的子类。

HttpServlet 类为 Servlet 接口提供了与 HTTP 协议相关的通用实现,十分适合开发基于 HTTP 协议的 Servlet 程序。由于 Servlet 主要用来处理 HTTP 的请求和响应,因此我们所编写的 Servlet 类通常都继承自 HttpServlet。

我们知道,在 HTTP/1.1 协议中共定义了 7 种请求方式,即 GET、POST、HEAD、PUT、DELETE、TRACE 和 OPTIONS。

HttpServlet 针对每一种请求方式提供了一个相应的服务方法,例如 doGet()、doPost()、doHead()、doPut()、doDelete()、doTrace() 和 doOptions(),并为这些 doXxx() 方法都提供了默认的实现。

HttpServlet 在 GenericServlet 的基础上对 Servlet 接口中的 service() 方法进行了重写,该方法会先获取客户端的请求方式,然后根据请求方式调用对应 doXxx() 方法。因此,我们在通过继承 HttpServlet 抽象类创建 Servlet 类时,只需要根据客户端的请求方式重写指定的 doXxx() 方法即可。

由于我们使用的请求方式主要是 GET 和 POST,所以通过继承 HttpServlet 类创建 Servlet 时,只需要重写 doGet 或者 doPost 方法,代码如下。

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.io.PrintWriter;

/**
* @author C语言中网 http://c.biancheng.net
* 继承 HttpServlet 接口,重写doXxx方法,创建 Servlet
*/
public class MyHttpServlet extends HttpServlet {
    /**
     * 重写 doGet() 方法
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //使用PrintWriter.write()方法向前台页面输出内容
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        writer.write("C语言中文网:http://c.biancheng.net");
        writer.close();
    }

    /**
     * 重写 doPost() 方法
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //使用PrintWriter.write()方法gaifang向前台页面输出内容
        PrintWriter writer = resp.getWriter();
        writer.write("C语言中文网:http://c.biancheng.net");
        writer.close();
        doGet(req, resp);
    }
}

Servlet部署及应用

我们知道,Servlet 中是没有 main() 方法的,因此它不能像其他的 Java 程序一样独立运行,而是必须以 JavaWeb 组件的形式部署到 Servlet 容器中,由容器对它实例化,调用其中的方法。

JavaWeb应用

所谓 JavaWeb 应用,就是使用 Java 语言开发的 Web 站点(网站)。它由一组 Servlet/JSP、HTML 文件、相关 Java 类以及其他的资源组成,它可以在由各种供应商提供的 Servlet 容器中运行。从定义可知, Servlet 是 JavaWeb 应用的一个组件。

为了让 Servlet 容器顺利地找到 JavaWeb 应用的各个组件,Servlet 规范规定:JavaWeb 应用必须采用固定的目录结构,即每种组件在 JavaWeb 应用中都有固定的存放目录

以 Tomcat 为例,JavaWeb 应用通常都需要存放到 Tomcat 的 webapps 目录下。webapps 目录中的每一个子目录都是一个独立的 Web 应用,子目录的名字就是 Web 应用的名字,也被称为 Web 应用的上下文根。用户可以通过这个上下文根来访问 JavaWeb 应用中的资源。

webapps 的目录结构如下图。

alt

alt

Servlet生命周期

Servlet的生命周期就是 Servlet 从创建到销毁的过程。Servlet 的生命周期完全由 Servlet 容器管理,可以分为以下 3 个阶段:初始化阶段、运行时阶段、销毁阶段

Servlet 接口中提供了三个与生命周期相关的方法,它们分别是:init()、service()、destory()。所有的 Servlet 都必须直接或者间接实现这三个方法,它们都会在 Servlet 生命周期的不同阶段被 Servlet 容器调用。

初始化阶段

Servlet 初始化的步骤

Servlet 初始化阶段包括以下 4 个步骤:

  1. Servlet 容器加载 Servlet 类,把 Servlet 类的 class 文件中的数据读取到内存中去。
  2. Servlet 容器创建一个 ServletConfig 对象,ServletConfig 对象包含了 Servlet 的初始化配置信息。
  3. Servlet 容器会通过反射对 Servlet 进行实例化,创建相应的 Servlet 对象。
  4. Servlet 容器调用 Servlet 对象的 init() 方法进行初始化,并将 ServletConfig 对象作为参数传递给 Servlet 。通过 ServletConfig 对象即可获得当前 Servlet 的初始化参数信息。

注意:由于 Servlet 容器是通过 Java 的反射 API 来创建 Servlet 实例的,需要调用 Servlet 的默认构造方法(default constructor,即不带参数的构造方法),所以在我们在编写 Servlet 类时,不能只提供一个带参数的构造方法。

Servlet 初始化的时机

如果 Servlet 是专门负责在 Web 应用启动阶段为 Web 应用完成一些初始化操作的,那个该 Servlet 就应该在 Web 应用启动时被初始化。但对于大多数的 Servlet 而言,它们只需要在被客户端首次请求访问时再开始初始化即可。

init() 方法只会被调用一次

通常情况下,一个 Servlet 实例一旦初始化完成就会长期存在于服务器的内存中,直到服务器关闭或手动销毁。当客户端向 Servlet 容器发出 HTTP 请求访问某个 Servlet 时,Servlet 容器首先会对该请求进行解析,检查内存中是否已经有了该 Servlet 对象。如果有,就直接使用该 Servlet 对象;如果没有,就创建 Servlet 实例对象,然后通过调用 init() 方法实现 Servlet 的初始化工作。

对于每一个 Servlet 而言,在整个生命周期内,它的 init() 方法只会被调用一次。

运行时阶段

运行时阶段是 Servlet 生命周期中最重要的阶段。在这个阶段,Servlet 可以随时处理并相应来自客户端的请求。

Servlet 容器接收到来自客户端请求时,容器会针对该请求分别创建一个 ServletRequst(请求)对象和一个 ServletResponse(响应)对象,将它们以参数的形式传入 service() 方法内,并调用该方法对请求进行处理。

在 service() 方法中,Servlet 通过 ServletRequst 对象获取客户端的相关信息和请求信息。在请求处理完成后,再通过 ServletResponse 对象将响应信息进行包装,返回给客户端。Servlet 容器将响应信息返回给客户端后,ServletRequst 对象与 ServletResponse 对象就会被销毁

在 Servlet 的整个生命周期内,对于 Servlet 的每一次请求,Servlet 容器都会调用一次 service() 方法,并创建新的 ServletRequest 和 ServletResponse 对象。即 service() 方法在 Servlet 的整个生命周期中会被调用多次

销毁阶段

当 Servlet 容器关闭、重启或移除 Servlet 实例时,容器就会调用 destroy() 方法,释放该实例使用的资源,例如:关闭数据库连接,关闭文件的输入流和输出流等,随后该实例被 Java 的垃圾收集器所回收。

对于每个 Servlet 实例来说,在整个生命周期内,它的 destroy() 方法只会被调用一次。

Servlet 生命周期执行流程

alt

在 Servlet 的整个生命周期中,创建 Servlet 实例、init() 方法和 destory() 方法都只执行一次。当初始化完成后,Servlet 容器会将该实例保存在内存中,通过调用它的 service() 方法,为接收到的请求提供服务。

@WebServlet 注解

@WebServlet 注解始于Servlet 3.0,它可以将一个普通的 Java 类声明为 Servlet,它解决了Servlet数量过多时web.xml文件配置得冗长繁琐的问题,其常用属性如下表: alt

@WebServlet 注解的使用

1. 启用注解支持

在 web.xml 的顶层标签 中有一个名为 metadata-complete 的属性。若该属性设置为 true,则 Servlet 容器在部署应用时将只依赖 web.xml,忽略所有的注解;若不配置该属性,或者将其设置为 false,则表示启用注解支持

metadata-complete 属性的默认值为 false,也就是说 Web 应用默认是启用 Servlet 注解支持的,因此我们在使用 @WebServlet 注解时,默认情况下是可以不创建 web.xml 文件的。

2. 使用 @WebServlet 注解

@WebServlet 是一个类(class)级别的注解,需要标注在继承了 HttpServlet 的 Servlet 类之上。其常用的写法是将 Servlet 的相对请求路径(即 value)直接写在注解内,例如:

@WebServlet(urlPatterns = { "/myServlet", "/myServlet2" })
public class MyServlet extends HttpServlet {
    ....
}

当 @WebServlet 中需要设置多个属性时,各属性之间必须使用逗号隔开,例如:

 @WebServlet(asyncSupported = true, name = "annotationServlet", description = "name描述", loadOnStartup = 1, urlPatterns = {"/annotationServlet"}, initParams = {@WebInitParam(name = "C语言中文网", value = "http://c.biancheng.net", description = "init参数1"), @WebInitParam(name = "京东", value = "https://www.jd.com/", description = "init参数2")})
public class AnnotationServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
}

@WebServlet VS web.xml

使用 web.xml 或 @WebServlet 注解都可以配置 Servlet, 两者各有优缺点。

1、@WebServlet 注解配置 Servlet

优点: @WebServlet 直接在 Servlet 类中使用,代码量少,配置简单。每个类只关注自身业务逻辑,与其他 Servlet 类互不干扰,适合多人同时开发。

缺点: Servlet 较多时,每个 Servlet 的配置分布在各自的类中,不便于查找和修改。

2、web.xml 配置文件配置 Servlet

优点: 集中管理 Servlet 的配置,便于查找和修改。

缺点: 配置较繁琐,可读性不强,不易于理解。

注意: 当web.xml文件中和@WebServlet注解同时存在时,@WebServlet中的url-pattern不能和web.xml文件中标签的映射内容完全相同,否则Tomcat启动时会报错:Caused by: java.lang.IllegalArgumentException: 名为 [RequestHeaderServlet]和 [net.biancheng.c.RequestHeaderServlet] 的servlet不能映射为一个url模式(url-pattern) [/getRequestHeader]

alt

alt

二者要么只能出现一个,要么url-pattern配置为不同。

Servlet虚拟路径映射

1、虚拟路径

我们知道,Web 应用被发布到服务器中之后,用户只需要打开浏览器请求正确的 URL 地址,就能够对该 Web 应用中的资源进行访问。

URL 是 Uniform Resource Locator 的缩写,译为“统一资源定位符”,它是专门为标识网络上的资源位置而设计的一种编址方式。通常以下由 3 部分组成: 应用层协议, 主机 IP 地址: 端口号或者域名 资源所在的路径/文件名

URL 的格式如下:

应用层协议://主机 IP 地址:端口号或域名/资源所在路径/文件名

例如,当我们想要对本地 Tomcat 服务器中的 index.html 进行访问时,只需要在浏览器中输入以下 URL 即可。 http://127.0.0.1:8080/servletDemo/html/index.html 其中,http 就是 URL 的应用层协议;127.0.0.1 就是服务器所在主机的 IP 地址;8080 是服务器端口号;

而剩余的 servletDemo/html/index.html就是资源所在的目录/文件名。

servletDemo:是 Web 应用的根目录名,或者说是 Web 应用名称; html :是资源所在的目录;

index.html:是真正想要访问的资源文件。

Servlet 规范规定,JavaWeb 应用在发布到 Web 服务器中之后必须采用固定的目录结构。其中,\WEB-INF\classes 目录就是用来存放各种 .class(字节码)文件或者包含 .class 文件的目录的。

但 WEB-INF 是 JavaWeb 应用的安全目录,只有服务器端才能访问,客户端无法直接访问。如果客户端想在页面中直接访问 WEB-INF 中 Servlet,就必须通过 web.xml 文件或 @WebServlet 注解为这个要访问的 Servlet 指定一个 URL 地址。

由于这个用于访问 Servlet 的 URL 地址并非 Servlet 真正的物理地址(实际存放在硬盘上的存储位置),而是我们通过 web.xml 或 @WebServlet 注解自行指定的,因此这个 URL 也被称为虚拟路径

2、虚拟路径映射

Servlet 虚拟路径映射就是,将 Servlet 与虚拟路径的对应起来的过程。

Servlet 虚拟路径映射可以被分为 2 类: 单一映射、多重映射

2.1 单一映射

Servelt 单一映射是指一个 Servlet 只被映射到一个虚拟路径上。

我们可以 Web 应用的 web.xml 文件中,使用 和 元素实现 Servlet 的单一映射。

例如,我们可以在 JavaWeb 应用 servletProject 的 web.xml 中,对 net.biancheng.c.MyServlet 类进行如下配置,实现对该 Servlet 的单一映射。

<?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_6_0.xsd"
         version="6.0">
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>net.biancheng.c.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/myServlet</url-pattern>
    </servlet-mapping>
</web-app>

上述代码中, 元素用于注册 Servlet,它包含两个主要的子元素 和 ,分别用于指定 Servlet 的名称和 Servlet 的完整限定名(包名+类名)。 元素用于定义 Servlet 与虚拟路径之间的映射,它包含两个子元素 和 ,分别用于指定 Servlet 的名称和虚拟路径。

在本例中, 元素的值为“/myServlet”,因此访问 net.biancheng.c.MyServlet 类的 URL 为“http://localhost:8080/servletProject/myServlet”。

2.2 Servlet 多重映射

我们还可以将一个 Servlet 映射到多个虚拟路径上,此时客户端通过其中任意的一个虚拟路径,都可以实现对该 Servlet 的访问,这就是 Servlet 的多重映射。

在 web.xml 中,Servlet 多重映射的配置方式有 2 种:

1、配置多个servlert-mapping元素:

    <servlet>
        <servlet-name>MappingServlet</servlet-name>
        <servlet-class>net.biancheng.c.MappingServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MappingServlet</servlet-name>
        <url-pattern>/mapping</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>MappingServlet</servlet-name>
        <url-pattern>/mapping2</url-pattern>
    </servlet-mapping>

2、配置多个url-pattern子元素:

    <servlet>
        <servlet-name>MappingServlet</servlet-name>
        <servlet-class>net.biancheng.c.MappingServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MappingServlet</servlet-name>
        <url-pattern>/mapping</url-pattern>
        <url-pattern>/mapping3</url-pattern>
    </servlet-mapping>

Servlet虚拟路径匹配

Servlet 虚拟路径有以下 4 种匹配规则:完全路径匹配、目录匹配、扩展名匹配、缺省匹配(默认匹配): alt

匹配优先级: Servlet 虚拟路径的匹配优先级顺序为:全路径匹配(精确匹配)> 目录匹配 > 扩展名匹配 > 缺省匹配(默认匹配)。

ServletConfig接口

jakarta.servlet 包提供了一个 ServletConfig 接口,该接口中提供了以下方法: alt Servlet 容器在初始化 Servlet 时,会为这个 Servlet 对象创建一个 ServletConfig 类型的对象,该对象中包含了该 Servlet 的初始化参数信息。在 Servlet 容器在调用 init() 方法时,会把这个 ServletConfig 对象作为参数传递给 Servlet 对象,通过这个 ServletConfig 对象即可获得当前 Servlet 的初始化参数信息。

Servlet 与 ServletConfig 对象之间是一一对应的关系,即 一个 Servlet 对象仅与一个 ServletConfig 对象对应,且 ServletConfig 对象中包含的 Servlet 初始化参数仅对当前 Servlet 才有效。

但是我们知道,一个 JavaWeb 应用中是可以包含多个 Servlet 的,因此 JavaWeb 应用中是可以存在多个 ServletConfig 对象的。

配置 Servlet 初始化参数

2种方式:1、使用 @WebServlet 配置初始化参数;2、使用 web.xml 配置初始化参数

使用 @WebServlet 配置初始化参数

通过 @WebServlet 注解提供的 initParams 属性为当前的 Servlet 设置初始化参数,示例代码如下:

package net.biancheng.c;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;

import java.io.IOException;

@WebServlet(urlPatterns = {"/MyServlet"}, initParams = {@WebInitParam(name = "name", value = "c语言中文网"),
        @WebInitParam(name = "url", value = "http://c.biancheng.net")})
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

使用 web.xml 配置初始化参数

<?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_6_0.xsd"
         version="6.0">

    <servlet>
        <servlet-name>configServlet</servlet-name>
        <servlet-class>net.biancheng.c.ConfigServlet</servlet-class>

        <!--设置初始化参数-->
        <init-param>
            <param-name>姓名</param-name>
            <param-value>小李</param-value>
        </init-param>
        <!--设置初始化参数-->
        <init-param>
            <param-name>年龄</param-name>
            <param-value>19</param-value>
        </init-param>
        <!--设置初始化参数-->
        <init-param>
            <param-name>性别</param-name>
            <param-value>男</param-value>
        </init-param>
        <!--设置初始化参数-->
        <init-param>
            <param-name>爱好</param-name>
            <param-value>篮球、足球、乒乓球</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>configServlet</servlet-name>
        <url-pattern>/config</url-pattern>
    </servlet-mapping>
</web-app>

获取 Servlet 初始化参数

package net.biancheng.c;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

@WebServlet(name = "ConfigServlet", value = "/ConfigServlet")
public class ConfigServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        // 获取ServletConfig对象
        ServletConfig config = getServletConfig();
        // 返回 servlet 的初始化参数的名称的集合
        Enumeration<String> initParameterNames = config.getInitParameterNames();
        // 遍历集合获取初始化参数名称
        while (initParameterNames.hasMoreElements()) {
            // 获取初始化参数名称
            String initParamName = initParameterNames.nextElement();
            // 获取相应的初始参数的值
            String initParamValue = config.getInitParameter(initParamName);
            // 向页面输出
            writer.write(initParamName + "  :  " + initParamValue + "<br/>");
        }
        // 关闭流
        writer.close();
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

Servlet上下文(ServletContext接口)

jakarta.servlet 包中提供了一个名为 ServletContext 的接口,它是 Servlet 与 Servlet 容器之间直接通信的接口。

Servlet 容器在启动一个 Web 应用时,会为该 Web 应用创建一个唯一的 ServletContext 对象,该对象一般被称为 “Servlet 上下文” ,其生命周期从 Servlet 容器启动时开始,直到容器关闭或应用被卸载时结束。

Web 应用中的所有 Servlet 都共享同一个 ServletContext 对象,不同 Servlet 之间可以通过 ServletContext 对象实现数据的传递与共享,因此 ServletContext 对象也被称为* Context 域对象*。

我们可以把 ServletContext 对象形象地理解为 Web 应用的总管家,同一个 Web 应用中的所有 Servlet 对象都共享一个总管家,Servlet 对象们可以通过这个总管家访问容器中的各种资源。

获得 ServletContext 对象的4种方式

  1. 通过 GenericServlet 提供的 getServletContext() 方法
//通过 GenericServlet的getServletContext方法获取ServletContext对象
ServletContext servletContext = this.getServletContext();
  1. 通过 ServletConfig 提供的 getServletContext() 方法
//通过 ServletConfig的 getServletContext方法获取ServletContext对象
ServletContext servletContext = this.getServletConfig().getServletContext();
  1. 通过 HttpSession 提供的 getServletContext() 方法
//通过 HttpSession的 getServletContext方法获取ServletContext对象
ServletContext servletContext = req.getSession().getServletContext();
  1. 通过 HttpServletRequest 提供的 getServletContext() 方法
//通过 HttpServletRequest的 getServletContext方法获取ServletContext对象
ServletContext servletContext = req.getServletContext();

ServletContext 的应用

ServletContext 接口定义了多个实用的方法,这些方法主要有以下 3 种应用。

  • 获取上下文初始化参数
  • 实现 Servlet 之间的数据通讯
  • 读取 Web 应用下的资源文件

1. 获取上下文初始化参数

我们可以通过 web.xml 中的 元素,为 Web 应用设置一些全局的初始化参数,这些参数被称为上下文初始化参数。

<?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_6_0.xsd"
         version="6.0">

    <!--设置全局初始化参数 -->
    <context-param>
        <param-name>name</param-name>
        <param-value>c语言中文网</param-value>
    </context-param>

    <context-param>
        <param-name>url</param-name>
        <param-value>http://c.biancheng.net</param-value>
    </context-param>
   
</web-app>

下表列举了 ServletContext 接口中用于获取上下文初始化参数的常用方法(和ServletConfig接口用法很像): alt

2. 数据通讯 —— 通过ServletContext 中的属性实现

我们还可以通过 ServletContext 接口中提供的方法创建一些自定义属性,保存在 ServletContext 对象中。每一个自定义属性都由一个属性名(name)和一个属性值(value)组成。

这些自定义属性可以被应用中所有的 Servlet 所共享,应用中所有的 Servlet 都可以对这些属性进行操作和访问,进而实现应用中不同 Servlet 之间的数据通讯。

下表列举了 ServletContext 接口中用于实现数据通讯的相关方法。 alt 虽然 ServletContext 的属性与上下文初始化参数都是存放在 ServletContext 对象中,但两者是不同的。 alt

3. 读取 Web 应用下的资源

ServletContext 接口专门定义了一些读取 Web 资源的方法 ,如下表: alt

下面我们通过一个简单的例子,来演示下如何使用 ServletContext 对象读取资源文件,步骤如下。

  1. 在 ServletContextProject 的 WEB-INF 目录新建一个 file 目录,并在该目录下创建一个名称为 db.properties 的文件,文件中输入如下所示的配置信息。
name=C语言中文网
url=http://c.biancheng.net
desc=精美而实用的网站,分享优质编程教程,帮助有志青年。千锤百炼,只为大作;精益求精,处处斟酌;这种教程,看一眼就倾心。
  1. 在 net.biancheng.c 包中,创建一个名称为 FileServlet 的 Servlet 类,代码如下所示。
package net.biancheng.c;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;

import java.io.*;
import java.util.Properties;

@WebServlet("/FileServlet")
public class FileServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        // 获取相对路径中的输入流对象
        InputStream ins = getServletContext().getResourceAsStream("/WEB-INF/file/db.properties");
        //防止中文乱码
        BufferedReader reader = new BufferedReader(new InputStreamReader(ins, "UTF-8"));

        // 获取输入流
        Properties pro = new Properties();
        // 加载
        pro.load(reader);
        // 获取文件中的内容
        String name = pro.getProperty("name");
        String url = pro.getProperty("url");
        String desc = pro.getProperty("desc");

        writer.write("名称:" + name + "<br/>" + "地址:" + url + "<br/>" + "描述:" + desc + "<br/>");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}
  1. 启动 Tomcat 服务器,在地址栏中输入“http://localhost:8080/ServletContextProject/FileServlet”,访问 FileServlet,结果如下图。 alt
#Java##Servlet#
全部评论
Servlet太卷了,划水都学不动
点赞 回复 分享
发布于 03-01 22:23 四川

相关推荐

AI牛可乐:哇,听起来你很激动呢!杭州灵枢维度科技听起来很厉害呀~你逃课去白马培训,老冯会同意吗?不过既然你这么感兴趣,肯定是有原因的吧! 对了,想了解更多关于这家公司或者求职相关的问题吗?可以点击我的头像私信我哦,我可以帮你更详细地分析一下!
你都用vibe codi...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务