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初始化方法,在服务器启动时调用该方法* 该方法只执行一次* */@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()是最常用的


  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 {@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的配置信息的:

  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.mzph.cn/news/192178.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EasyExcel写入多个sheet

直接上代码&#xff1a; public static void main(String[] args) {// 设置excel工作簿ExcelWriter excelWriter EasyExcel.write("F:\\excel\\a.xls").build();List<User> userList new ArrayList<>();userList.add(new User("lisi", "…

初始数据结构(加深对旋转的理解)

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/rotate-array/submissions/ 与字…

11.1每日一题(关于函数定义域)

f(x1)&#xff1a;自变量为x&#xff0c;x1为中间变量&#xff0c;所以f(x1)的定义域的取值范围是x的取值范围 f(x)&#xff1a;自变量为x&#xff0c;f(x)的定义域等价于f(x1)中 x1整体的定义域

深度学习记录--logistic回归损失函数向量化实现

前言 再次明确向量化的目的&#xff1a;减少for循环的使用&#xff0c;以更少的代码量和更快的速度来实现程序 正向传播的向量化 对于,用向量化来实现&#xff0c;只需要就可以完成&#xff0c;其中,, ps.这里b只是一个常数&#xff0c;但是依然可以加在每个向量里(python的…

09-命令者模式-C语言实现

命令者模式是一个高内聚的模式&#xff0c; 其定义为&#xff1a; Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.&#xff08;将一个请求封装成一个对象&…

JDK17的安装与配置

JDK17的安装与配置 下载地址安装步骤配置环境变量验证安装是否成功 下载地址 此jdk17安装的系统是win10系统 https://www.oracle.com/java/technologies/downloads/ 这里选择JDK17进行下载 下载完成之后&#xff0c;显示如下图&#xff1a; 安装步骤 自定义的安装路径&…

智能优化算法应用:基于探路者算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于探路者算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于探路者算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.探路者算法4.实验参数设定5.算法结果6.参考文献7.…

动态规划------方法汇总

核心&#xff1a; 状态定义 状态转移方程 启发思路&#xff08;两种情况&#xff09;&#xff1a;选 或 不选 / 选哪个 DP三步&#xff1a;先写回溯&#xff0c;时间复杂度 指数级别&#xff1b;递归的过程中会重复计算&#xff0c;要保存计算结果&#xff0c;递归搜索…

Windows微软常用运行库合集2023

微软常用运行库合集适用于Windows系统的运行库合集包&#xff0c;基于微软官方的运行库而制作的&#xff0c;包括了常用的vb&#xff0c;vc2005/2008/2010/2012/2013/2017/2019/2005-2022&#xff0c;Microsoft Universal C Runtime&#xff0c;VS 2010 Tools For Office Runti…

Programming Contest 2023(AtCoder Beginner Contest 331)D题 Tile Pattern --- 题解

目录 D - Tile Pattern 题目大意&#xff1a; 思路&#xff1a; 代码&#xff1a; D - Tile Pattern D - Tile Pattern (atcoder.jp) 题目大意&#xff1a; 给你一个n和q&#xff0c;n为局部棋盘大小(n*n) 并且给出局部棋盘中黑白子位置的放置情况&#xff0c;q为查询次数…

某60区块链安全之Create2实战一学习记录

区块链安全 文章目录 区块链安全Create2实战一实验目的实验环境实验工具实验原理实验内容Create2实战一 实验步骤分析合约源代码漏洞Create2实战一 实验目的 学会使用python3的web3模块 学会分析以太坊智能合约Create2引发的漏洞及其利用 找到合约漏洞进行分析并形成利用 实…

淘宝/天猫商品详情API接口丨京东商品详情丨1688商品详情丨接口key密钥获取方式

要获取淘宝/天猫商品详情API接口、京东商品详情API接口、1688商品详情API接口以及接口密钥&#xff08;Key&#xff09;&#xff0c;可以按照以下步骤进行操作&#xff1a; 注册并登录淘宝/天猫开发者中心或京东开放平台或1688开放平台&#xff0c;并创建应用。在创建应用的过…

GODOC命令无效,原因是需要手动安装

在看《GO程序设计语言》这本书&#xff0c;按照其中的内容&#xff0c;想看下GO自带的包的文档。 书中讲&#xff0c;可以直接输入GoDOC命令来打开一个服务器&#xff0c;从而可以用浏览器访问文档库。输入命令后&#xff0c;系统提示找不到该命令。 查了资料后才发现&#xff…

6-55.汽车类的继承

根据给定的汽车类vehicle&#xff08;包含的数据成员有车轮个数wheels和车重weight&#xff09;声明&#xff0c;完成其中成员函数的定义&#xff0c;之后再定义其派生类并完成测试。 小车类car是它的派生类&#xff0c;其中包含载人数passenger_load。每个类都有相关数据的输出…

解决Wireshark分析RTMP抓包时Unknown问题

使用Wireshark抓包时&#xff0c;经常出现很多Unknown包&#xff0c;但实际上的字节流实际是正常的。 其实&#xff0c;RTMPT设置里有一个最大包大小的设置&#xff0c;默认是32768&#xff0c;而且默认RTMPT协议配置了从多个TCP流中重组RTMPT的功能(应当是考虑基于HTTP的传输…

Redis RDB

基于内存的 Redis, 数据都是存储在内存中的。 那么如果重启的话, 数据就会丢失。 为了解决这个问题, Redis 提供了 2 种数据持久化的方案: RDB 和 AOF。 RDB 是 Redis 默认的持久化方案。当满足一定条件的时候, 会把当前内存中的数据写入磁盘, 生成一个快照文件 dump.rdb。Redi…

Day48力扣打卡

打卡记录 最大化城市的最小电量&#xff08;二分前缀和差分数组贪心&#xff09; 链接 class Solution:def maxPower(self, stations: List[int], r: int, k: int) -> int:n len(stations)sum list(accumulate(stations, initial0))for i in range(n):stations[i] sum[…

vscode插件离线下载

离线下载插件地址&#xff1a;https://marketplace.visualstudio.com/VSCode

elasticsearch 内网下如何以离线的方式上传任意的huggingFace上的NLP模型(国内闭坑指南)

es自2020年的8.x版本以来&#xff0c;就提供了机器学习的能力。我们可以使用es官方提供的工具eland&#xff0c;将hugging face上的NLP模型&#xff0c;上传到es集群中。利用es的机器学习模块&#xff0c;来运维部署管理模型。配合es的管道处理&#xff0c;来更加便捷的处理数据…

vcomp140.dll是什么意思?vcomp140.dll缺失怎么修复的五个方法

在电脑使用过程中&#xff0c;我们常常会遇到一些错误提示&#xff0c;其中之一就是“由于找不到vcomp140.dll无法继续执行代码”。这个错误提示通常出现在运行某些程序时&#xff0c;给使用者带来了很大的困扰。那么&#xff0c;为什么会出现这个错误呢&#xff1f;又该如何解…