当前位置: 首页 > article >正文

Java Web——动态Web开发核心-Servlet

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"

具体步骤:

  1. 用IDEA创建一个项目,配置好Tomcat服务器


  1. 添加servlet-api.jar(在tomcat/lib下) 到工程, 因为servlet.jar 不是jdk自带的, 要引入

这里用两种方法:一个是自己导入实体Tomcatlib文件夹下的servlet的jar包

二是在pom文件配置联网下载Servlet的jar包


  1. 创建HelloServlet.java类,并实现Servlet接口
package com.example;

import javax.servlet.*;

//创建一个Servlet类,要实现Servlet接口
//实现接口的5个方法,但常用的是3个

public class HelloServlet implements Servlet {

    /*
    * 该方法常用
    * init初始化方法,在服务器启动时调用该方法
    * 该方法只执行一次
    * */
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("init方法被调用~");
    }

    /*
    * getServletConfig方法
    * 返回ServletConfig 也就是返回ServLet的配置
    * */
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /*
    * 该方法使用的非常多
    * service方法,在服务器接收到请求时(含get/post方法)调用该方法
    * 该方法每次请求都会被调用
    * 该方法会把http请求转为Java对象,进行一系列操作
    * 处理请求之后会把Java对象转为http响应,返回给客户端
    * */
    @Override
    public void service(ServletRequest req, ServletResponse res) {
    	System.out.println("Hello Servlet!");
    }
    
    /*
    * getServletInfo方法
    * 返回Servlet的描述信息*/
    @Override
    public String getServletInfo() {
        return null;
    }

    /*
     * 该方法常用
     * destroy销毁方法,
     * 在服务器关闭时调用该方法
     * 该方法只执行一次
     * */
    @Override
    public 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()是最常用的


  1. 在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。

  1. 运行启动Tomcat服务器

在浏览器输入对应的地址并回车

IDEA控制台显示刚才在Servlet方法中的输出信息

如果此时多次刷新该页面,控制台会多次输出 “Hello Servlet”


3.1. 浏览器调用Servlet的流程

第一次HTTP请求:(也就是在浏览器地址栏输入回车对应的地址)

  1. 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>中去

  1. Tomcat会调用Servlet类的service()方法来处理HTTP请求。

在service()方法中,可以根据请求的类型(GET、POST等)和URL路径来确定 具体要执行的方法。

  1. 执行完service()方法后,Tomcat会返回响应给客户端。
  2. Tomcat会根据需要销毁或重新实例化Servlet类,以供下一次请求使用。

第二次及以后的相同HTTP请求,Tomcat会执行以下步骤:

  1. Tomcat接收到HTTP请求后,会根据请求的URL路径在web.xml中进行匹配,找到对应的Servlet类或URL Pattern。
  2. Tomcat会根据匹配结果直接调用已经实例化的Servlet类的service()方法来处理HTTP请求。
  3. 在service()方法中,可以根据请求的类型(GET、POST等)和URL路径来确定具体要执行的方法。
  4. 执行完service()方法后,Tomcat会返回响应给客户端。

对于第二次及以后的相同HTTP请求,Tomcat会有以下的不同:

  • Tomcat会直接根据之前已经实例化的Servlet类来处理请求,而不需要再次实例化。
  • Tomcat会直接调用已经初始化的Servlet类的service()方法来处理请求,而不需要再次调用init()方法进行初始化。

3.2. Servlet生命周期

  1. Servlet生命周期概述

Servlet的生命周期是指从创建Servlet对象到销毁Servlet对象的过程。这个过程包括三个阶段:初始化(init)、服务(service)和销毁(destroy)。

  1. 初始化阶段(init):当Servlet第一次被加载到内存时,Servlet容器会调用Servlet的init()方法进行初始化。init()方法在Servlet的整个生命周期中只会被调用一次。
  2. 服务阶段(service):当客户端发送请求时,Servlet容器会调用service()方法来处理客户端的请求。service()方法可以处理GET、POST等不同类型的请求。
  3. 销毁阶段(destroy):当Servlet不再需要时,Servlet容器会调用destroy()方法来销毁Servlet对象。在销毁阶段,Servlet对象将不再可用。

总之,Servlet的生命周期是指从创建Servlet对象到销毁Servlet对象的过程,包括初始化、服务和销毁三个阶段。


  1. Servlet容器

Servlet容器是一个运行环境,它负责创建Servlet对象,并调用Servlet的生命周期方法。Servlet容器负责管理Servlet的生命周期,包括初始化、服务和销毁阶段。

在Servlet的生命周期中,Servlet容器会调用Servlet的init()方法进行初始化,然后根据客户端的请求调用service()方法来处理请求。当Servlet不再需要时,Servlet容器会调用destroy()方法来销毁Servlet对象。


  1. 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中,因此更适合发送敏感或大量数据。

代码演示:

  1. 准备一个前端静态的注册页面
<!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>


  1. 后端Servlet写上相应的处理

后端的Servlet就用刚刚的HelloServlet,方便,web.xml也不用配置

注意:前端页面提交的数据是请求对象,但在service方法中的ServletRequest中并没有对应的方法去获取这个请求对象,怎么办,查看ServletRequest的子类是否有

但是ServletRequest类的实现类中的HttpServletRequest含有这个方法

显示下面这个界面是在IDEA中同时按下Ctrl+Alt再鼠标指向ServletRequest

该操作可以查看该接口的子接口和实现子类

所以就有了如下代码:

  1. 启动服务器,地址栏输入相关地址,并输入数据点击注册

  1. 结合上面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

  1. HttpServletRequest概念

HttpServletRequest是Java Servlet API中的一个核心接口,它代表了来自客户端的HTTP请求。这个接口提供了许多方法,用于获取请求的各种属性和参数,如请求的URI、请求方法、请求头信息、请求参数等。

当一个HTTP请求到达Servlet容器(如Tomcat)时,容器会将请求报文转换成一个HttpServletRequest对象,并将这个对象作为参数传递给Servlet的service方法。这样,Servlet就可以通过HttpServletRequest对象获取到所有关于该请求的信息,从而进行处理。


  1. 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

  1. HttpServletResponse概念

HttpServletResponse是Java Servlet API中的另一个核心接口,它代表了服务器对客户端的响应。这个接口提供了一些方法,用于设置响应头信息、输出响应内容、设置响应状态等。

当Servlet的service方法处理完请求后,它可以通过HttpServletResponse对象将响应内容写入到响应报文中,并将响应报文发送给客户端。通过HttpServletResponse对象,Servlet可以设置响应的状态码、响应头信息、响应内容等。


  1. 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注意事项

  1. 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 请求和响应进行交互。


  1. 对于每次请求,服务器通常只会创建一个Servlet实例,这个实例会一直存在直到Web应用程序被重新部署或服务器关闭。每个请求会得到一个新的对象实例来处理,但实例变量在每次请求后会被重置。当Web应用程序被重新部署或服务器重启时,所有的Servlet实例都会被销毁并重新创建,以确保正确运行。


  1. 在Servlet的生命周期中,init方法是只被调用一次的。这是因为Servlet的实例在服务器启动时就被创建,然后一直存在,直到Web应用程序被重新部署或服务器关闭。在Servlet的生命周期内,init方法只会在Servlet实例创建时被调用一次,用于初始化Servlet。
  2. 对于每次用户发出的请求,Servlet引擎都会调用一次Servlet的service方法。这个service方法会接收两个参数:HttpServletRequest请求对象和HttpServletResponse响应对象。这两个对象是Servlet引擎为每个请求创建的新的对象。
  3. 对于每次用户请求,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 {
    @Override
    protected 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 {
    @Override
    protected 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 {
     @Override
     protected 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的配置信息的:

  1. name():返回servlet的名字,默认为空字符串。
  2. value()urlPatterns():这两个方法是等价的,都是用来设置URL模式的。当请求匹配这些模式时,该servlet将被调用。
  3. loadOnStartup():设置servlet在应用启动时加载的顺序。默认值为-1,表示容器可自由选择加载时机。
  4. initParams():设置servlet的初始化参数。
  5. asyncSupported():声明servlet是否支持异步操作模式。如果为true,那么servlet可以使用startAsync()方法进行异步处理。
  6. smallIcon()largeIcon():分别设置servlet的小图标和大图标。默认都为空字符串。
  7. description():设置servlet的描述信息。默认为空字符串。
  8. displayName():设置servlet的显示名。默认为空字符串。

上面的例子就用到了name和urlPatterns,设定servlet的名字和它的URL地址


8.4. WebServlet注解原理

  1. 这是没有WebServlet注解的HTTP请求方式:
  2. 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>中去

  1. Tomcat会调用Servlet类的service()方法来处理HTTP请求。

在service()方法中,可以根据请求的类型(GET、POST等)和URL路径来确定 具体要执行的方法。

  1. 执行完service()方法后,Tomcat会返回响应给客户端。
  2. Tomcat会根据需要销毁或重新实例化Servlet类,以供下一次请求使用。

  1. 如果此时用了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下的资源。
  • 响应重定向可以转发到外部资源,即本项目以外的资源。

代码演示:



http://www.kler.cn/a/154653.html

相关文章:

  • Nginx 上安装 SSL 证书并启用 HTTPS 访问
  • 测试实项中的偶必现难测bug--互斥逻辑异常
  • 设计模式(四)装饰器模式与命令模式
  • 使用 npm 安装 Yarn
  • AR眼镜方案_AR智能眼镜阵列/衍射光波导显示方案
  • 【Linux网络编程】简单的UDP网络程序
  • TA-Lib学习研究笔记(八)——Momentum Indicators 中
  • TLS、对称/非对称加密、CA认证
  • Zabbix HA高可用集群搭建
  • Node.js 事件循环:定时任务、延迟任务和 I/O 事件的艺术
  • 编程实战:类C语法的编译型脚本解释器(五)
  • HarmonyOS——解决本地模拟器无法选择设备的问题
  • 编程实战:类C语法的编译型脚本解释器(三)
  • 2312skia,15vulkan及技巧
  • Go语言实现深度学习的正向传播和反向传播
  • 深入理解Servlet(上)
  • 深度学习记录--计算图(前向后向传播)
  • 最新AI智能写作回答系统源码 附完整的搭建教程
  • java学习part29线程通信
  • 锐捷EWEB网管系统 RCE漏洞复现
  • oracle sql相关语法
  • Docker的常用基本命令(基础命令)
  • 在Windows中如何知道当前cmd的python解释器来自哪个位置
  • 在 ArcGIS 软件中添加左斜宋体(东体)的方法与步骤
  • 管理类联考-性质
  • 无人机助力电力设备螺母缺销智能检测识别,python基于YOLOv7开发构建电力设备螺母缺销小目标检测识别系统