JavaWeb学习——Servlet介绍

news/2025/3/9 19:25:02/

Servlet 简介

什么是 Servlet

Servlet 是一种服务器端的 Java 技术,设计用于扩展 Web 服务器或应用服务器的功能。Servlet 主要运行在服务器端,用来处理来自客户端的请求并生成响应。它们是 Java 技术中处理 HTTP 请求和响应的核心组件之一。

servlet__8">servlet 的工作过程

  1. 客户端发起请求:用户通过浏览器或其他 HTTP 客户端发送一个 HTTP 请求到 Web 服务器。
  2. Web 容器接收请求:Web 容器(如 Apache Tomcat、Jetty 等)接收到 HTTP 请求后,根据请求中的 URL 信息决定哪个 Servlet 应该负责处理该请求。
  3. 调用 Servlet 实例:如果相应的 Servlet 尚未加载,则 Web 容器会先创建 Servlet 实例,并调用其 init() 方法进行初始化;如果 Servlet 已经被加载,则跳过此步骤。
  4. 处理请求:Web 容器将请求分派给对应的 Servlet 实例,然后调用它的 service() 方法。在这个方法里,Servlet 会根据请求类型(GET, POST 等)来选择适当的方法(例如 doGet(), doPost() 等)来处理请求。
  5. 生成响应:Servlet 处理完请求后,构建响应内容(如 HTML 页面、JSON 数据等),并通过响应对象返回给客户端。
  6. 销毁 Servlet:当 Web 应用程序关闭或重新部署时,Web 容器会调用 Servlet 的 destroy() 方法释放资源。

Servlet 特点

  • 持久性:Servlet 一旦被加载就保持在内存中,直到服务器关闭或应用重启,这使得 Servlet 可以高效地处理多个请求。
  • 线程安全:由于每个请求都是在一个独立的线程中处理的,因此需要考虑多线程环境下的线程安全问题。
  • 灵活性:可以通过配置文件或者注解的方式来配置 Servlet 的行为和映射规则。
  • 安全性:支持各种认证和授权机制,以保护对 Servlet 的访问。
  • 可移植性:基于 Java 语言编写,Servlet 可以在任何支持 Java 的平台上运行。

Servlet 的关键点

  1. 平台无关性:Servlet 是用 Java 编写的,因此它们具有 Java 语言的所有优点,包括跨平台能力。
  2. 多线程:Servlet 由 Web 容器(如 Apache Tomcat)管理,容器会为每个请求创建一个新线程,并将请求分派给 Servlet 实例。这使得 Servlet 能够处理多个并发请求。
  3. 生命周期:Servlet 的生命周期由 Web 容器控制,主要包括初始化(init)、服务(service)和销毁(destroy)三个阶段。
  4. HTTP 协议支持:虽然 Servlet 可以处理多种类型的请求,但它们最常用于处理 HTTP 请求。为此,Java Servlet API 提供了专门的类 HttpServlet,它简化了对 HTTP GET 和 POST 请求的处理。
  5. 部署描述符:Servlet 的配置信息通常保存在一个名为 web.xml 的文件中,该文件位于 WEB-INF 目录下。从 Servlet 3.0开始,也支持使用注解来配置 Servlet。
  6. 安全性:可以通过安全约束和用户认证等机制来保护 Servlet 资源的安全。
  7. 状态管理:Servlet 可以通过使用会话跟踪机制(例如,通过 URL 重写、隐藏表单字段或 Cookies)来维护客户端的状态信息。
  8. 性能:因为 Servlet 实例在容器启动时加载并在内存中持久化,所以它们比 CGI 脚本更高效,后者每次请求都会创建新的进程。
  9. API:Java Servlet API 定义了一组接口和类,开发人员可以使用这些接口和类来创建自己的 Servlet。
  10. 框架集成:现代 Web 开发通常不会直接使用 Servlet,而是依赖于建立在其上的高级框架,比如 Spring MVC 或 Jakarta EE 中的 JSF,这些框架提供了更高层次的抽象,简化了 Web 应用程序的开发。

在这里插入图片描述

Servlet 快速开发 Hello World

使用 java servlet 快速开发 hello world,需要满足以下步骤:

  1. 准备 java 和 tomcat 环境。
  2. 如果使用 maven 构建项目,需要导入 servlet 依赖。如果创建 javaWeb 项目,需要引入 tomcat jar包。
  3. 编写 servlet 类:创建一个新的 java 类,并让它继承自 HttpServlet。覆盖 doGet()doPost() 方法来处理 HTTP GET 或 POST 请求。
java">import java.io.*;
import javax.servlet.http.*;public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException {response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();out.println("<h1>Hello World! </h1>");}
}
  1. WEB-INF/web.xml 中添加:
<servlet><servlet-name>HelloServlet</servlet-name><servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello</url-pattern>
</servlet-mapping>
  1. 部署到 servlet 容器,有两种方法:

    • 使用 tomcat:将项目打包成 WAR 文件,放到 tomcat 的 webapps 目录下。

    • IDE 直接运行(如 IntelliJ 或 Eclipse):配置本地 tomcat 并启动。

  2. 启动服务器并测试:打开浏览器,输入 http://localhost:8080/你的项目名/hello,你应该能看到页面显示“Hello, World!”

servlet__94">servlet 映射注意事项

  • 一个 servlet-name 可以同时对应多个 url-pattern
<servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello1</url-pattern><url-pattern>/hello2</url-pattern>
</servlet-mapping>
  • 一个 servlet 标签可以同时对应多个 servlet-mapping 标签。

url-pattern 匹配规则:

  1. 精确匹配:/servlet
  2. 模糊匹配:
    • * 作为通配符,* 在哪里,哪里就是模糊的。
    • / 匹配全部,不包含 jsp 文件。
    • /* 匹配全部,包含 jsp 文件。
    • /xxx/* 匹配前缀,后缀模糊。
    • *.xxx 匹配后缀,前缀模糊。

servlet__120">servlet 注解方式配置

servlet 映射可以通过在 servlet 类上加上注解 @WebServlet 进行配置。

java">import java.io.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;@WebServlet("/hello")
public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException {response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();out.println("<h1>Hello World! </h1>");}
}

这样就可以不用编写 web.xml 文件了

servlet__146">servlet 的生命周期

生命周期简介

应用程序中的对象不仅在空间上有层次结构的关系,在时间上也会因为处于程序运行过程中的不同阶段而表现出不同状态和不同行为——这就是对象的生命周期。

简单来说,就是对象在容器中从开始创建到销毁的过程。

servlet__156">servlet 容器

servlet 对象是 servlet 容器创建的,生命周期方法都是由容器(目前是 tomcat)调用的,这一点和之前所编写的代码有很大不同,越往后面到框架,越来越多的对象就要交给容器或框架来创建,越来越多的方法由容器或框架来调用,开发人员要尽可能多的将精力放在业务逻辑的实现上。

servlet__162">servlet 的生命周期

servlet 的生命周期由其在 web 容器(如 Apache Tomcat)中的管理来定义,主要包括以下几个阶段:加载和实例化、初始化、服务请求以及销毁。以下是 servlet 生命周期的详细描述:

  1. 加载和实例化

当 web 容器接收到对特定 servlet 的第一个请求时,它会加载该 servlet 类并创建其实例。这个过程可以通过 web 容器自动完成,也可以通过配置让容器在启动时就加载某些 servlet

  • 注解方式:使用 @WebServlet 注解指定 url 映射。
  • 部署描述符(web.xml):在 web.xml 文件中配置 servlet 及其映射关系。
  1. 初始化(init)

一旦 servlet 实例被创建,容器就会调用其 init() 方法进行初始化。此方法只调用一次,用于执行一次性设置操作,比如建立数据库连接或初始化资源。

java">public void init() throws ServletException {// 初始化代码
}

注意事项:

  • 默认情况下,第一次收到请求时容器创建 servlet 实例并初始化。
  • 通过配置 loadOnStartup,可在容器启动时立即初始化。

配置方式:

java">@WebServlet(urlPatterns = "/hello", loadOnStartup = 1) // 数字越小优先级越高

或在 web.xml 中配置:

<servlet><servlet-name>HelloServlet</servlet-name><servlet-class>HelloServlet</servlet-class><load-on-startup>1</load-on-startup>
</servlet>

如果要自己配置时,建议从6开始配置,因为 tomcat 默认的 web.xml 中已经配置到了5。

  1. 服务(service)

初始化完成后,servlet 就可以处理客户端请求了。每当有请求到达时,容器都会调用 servletservice() 方法,并根据 http 请求类型(GET, POST 等),将请求分派给相应的 doGet(), doPost() 等方法。

java">protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 处理GET请求的代码
}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 处理POST请求的代码
}
  1. 销毁(destroy)

当 web 应用被关闭或者重新部署时,容器会调用 servletdestroy() 方法,允许 servlet 释放占用的资源,如关闭数据库连接等。之后,servlet 对象会被垃圾回收。

java">public void destroy() {// 清理代码
}

生命周期总结:

  • 加载和实例化:web 容器加载 servlet 类并创建其实例。
  • 初始化:容器调用 init() 方法进行必要的初始化工作。
  • 服务:容器调用 service() 方法处理客户端请求,根据请求类型调用不同的方法(如 doGet(), doPost())。
  • 销毁:当 web 应用停止或重载时,容器调用 destroy() 方法清理资源,随后 servlet 对象将被销毁。

了解 servlet 的生命周期对于有效地编写和调试 servlet 应用程序非常重要,因为它影响着资源的分配与释放、性能优化等方面。正确地实现这些生命周期方法可以帮助你更好地管理 servlet 的行为和状态。

注意事项

  • servlet 在 tomcat 中是单例的。
  • servlet 的成员变量在多个线程栈之中是共享的。
  • 不建议在 service() 方法中修改成员变量,因为在并发请求中,会引发线程安全问题。

DefaultServlet

打开 tomcat 下的 conf 目录下的 web.xml 文件可以看到:

<servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class><init-param><param-name>debug</param-name><param-value>0</param-value></init-param><init-param><param-name>listings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>

DefaultServlet 主要用于处理对静态资源的请求,比如 HTML 页面、图片、CSS 文件和 JavaScript 文件等。当部署的应用程序中的其他 Servlet 不处理某个请求时,就会由 DefaultServlet 来处理这些静态内容。

功能

  • 提供静态资源DefaultServlet 能够高效地从应用的目录结构中提供静态文件。
  • 支持范围请求:允许客户端请求部分文件内容,这对于大文件下载或断点续传功能特别有用。
  • 目录浏览:如果启用了目录浏览功能,当访问一个目录而非具体文件时,DefaultServlet 可以生成并返回该目录下的文件列表页面。
  • 缓存控制:通过设置响应头来控制浏览器缓存行为,提高性能。

servlet__284">servlet 继承结构

Servlet 接口

java">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 接口是 java servlet API 的核心部分,定义了所有 servlet 必须实现的方法。尽管大多数时候你会继承 HttpServlet 类而不是直接实现 servlet 接口(因为 HttpServlet 已经实现了 servlet 接口,并提供了便捷的方法来处理 HTTP 请求),了解 servlet 接口定义的基本方法对于理解 servlet 的工作原理是非常有帮助的。以下是 servlet 接口中定义的主要方法:

  1. void init(ServletConfig config)
  • 用途:当 servlet 被 Web 容器加载并实例化后,会调用此方法进行初始化。这个方法只会被调用一次。
  • 参数ServletConfig 对象包含 servlet 的配置信息和初始化参数。
  • 注意:通常情况下,你不需要直接实现这个方法,除非你需要执行特定的初始化操作。
  1. void service(ServletRequest req, ServletResponse res)
  • 用途:这是 servlet 的核心方法,每当收到客户端请求时都会调用此方法来处理请求并生成响应。
  • 参数
    • ServletRequest:封装了客户端请求的所有信息。
    • ServletResponse:提供给 servlet 用来返回响应给客户端的方式。
  • 注意:直接实现 servlet 接口时需要重写此方法来处理不同类型的请求。但是,如果你继承自 HttpServlet,通常不需要直接覆盖 service() 方法,而是根据请求类型(GET、POST 等)重写相应的方法(如 doGet(), doPost() 等)。
  1. void destroy()
  • 用途:当 servlet 将要从服务中移除时,Web 容器会调用此方法。它用于释放 servlet 占用的资源。
  • 注意:这是一个清理工作的机会,比如关闭数据库连接等。
  1. ServletConfig getServletConfig()
  • 用途:返回一个 ServletConfig 对象,该对象包含了 servlet 的初始化参数和配置信息。
  • 用途:可用于获取在部署描述符(如 web.xml)中为 servlet 指定的初始化参数。
  1. String getServletInfo()
  • 用途:返回关于 servlet 的信息字符串,比如作者、版本和版权等信息。
  • 注意:虽然这不是必需实现的功能,但它可以为维护人员提供有用的信息。

实现细节

虽然可以直接实现 servlet 接口,但在实际开发中,更常见的是扩展 HttpServlet 抽象类,因为它简化了许多任务,特别是处理 HTTP 请求的过程。HttpServlet 已经实现了上述方法,并提供了额外的方法如 doGet(), doPost() 等,专门用于处理 HTTP GET 和 POST 请求。

通过继承 HttpServlet,你可以专注于重写适合你的应用需求的方法,而无需关心底层协议的具体实现细节。这样不仅提高了开发效率,也使得代码更加简洁易读。

GenericServlet 抽象类

GenericServlet 是一个抽象类,它实现了 ServletServletConfigSerializable 接口,简化了直接实现 Servlet 接口的复杂度。尽管 GenericServlet 可以用于任何类型的协议,但它通常被设计为与 HTTP 协议无关的基础类。对于开发基于 HTTP 的应用,更常用的是它的子类 HttpServlet

主要特点

  • 通用性GenericServlet 提供了一个不依赖于任何特定协议的框架,可以用来创建非 HTTP servlet
  • 简化配置管理:通过实现 ServletConfig 接口,GenericServlet 提供了对初始化参数的便捷访问方法。
  • 生命周期管理:实现了 init() 方法,使得开发者只需重写 service() 方法来处理请求,而不需要担心其他生命周期方法的具体实现。

核心方法

  1. init(ServletConfig config)
    • 调用超类的 init(config) 来保存配置对象,并允许子类进行自定义的初始化操作。
  2. init()
    • 一个无参的 init() 方法,被上述带参数的 init(ServletConfig config) 自动调用。如果需要执行自定义的初始化逻辑,可以覆盖此方法。
  3. service(ServletRequest req, ServletResponse res)
    • 必须由子类实现的方法,用于处理客户端请求。该方法接收一个 ServletRequest 对象和一个 ServletResponse 对象作为参数,分别代表请求和响应。
  4. getServletConfig()
    • 返回 ServletConfig 对象,该对象包含了 servlet 的初始化参数。
  5. getServletContext()
    • 返回 ServletContext 对象,提供了一种与整个 Web 应用程序通信的方式。
  6. getServletInfo()
    • 返回关于 servlet 的信息字符串,比如作者、版本等。默认返回空字符串,可以根据需要覆盖。
  7. destroy()
    • servlet 即将被卸载时,容器会调用此方法,以便释放资源。默认为空实现,可以根据需要添加清理代码。

虽然 GenericServlet 提供了一些便利,但在实际开发中,特别是针对 Web 应用,更多时候会选择继承 HttpServlet 类,因为它提供了更具体的支持来处理 HTTP 请求(如GET、POST等),从而减少了手动解析协议的需求。然而,了解 GenericServlet 对于理解 Servlet API 的基本机制仍然很有帮助。

HttpServlet 抽象类

HttpServlet 是一个抽象类,它是 GenericServlet 的子类,专门设计用于处理基于 HTTP 协议的请求。通过继承 HttpServlet 类,开发者可以更容易地编写处理 HTTP GET、POST 等请求的 servletHttpServlet 提供了便捷的方法来处理这些常见的 HTTP 请求方法,使得开发人员不需要直接操作低级别的 ServletRequestServletResponse 对象。

主要特点

  • 专注于 HTTPHttpServlet 专为 HTTP 协议设计,提供了针对 HTTP 请求(如 GET、POST 等)的特定方法。
  • 简化开发:通过提供预定义的方法如 doGet(), doPost() 等,简化了 HTTP 请求的处理过程。
  • 扩展性强:虽然 HttpServlet 是抽象类,但其提供的默认实现足以应对很多场景,只需根据需要覆盖相应的方法即可。

核心方法

尽管 HttpServlet 包含多个方法,但对于大多数应用而言,最常被重写的方法包括:

  1. doGet(HttpServletRequest req, HttpServletResponse resp)
    • 处理 HTTP GET 请求。通常用于从服务器检索信息而不改变服务器状态。
  2. doPost(HttpServletRequest req, HttpServletResponse resp)
    • 处理 HTTP POST 请求。适用于向服务器发送数据并可能改变服务器状态的情况,例如提交表单。
  3. doPut(HttpServletRequest req, HttpServletResponse resp)
    • 处理 HTTP PUT 请求。通常用于上传内容到指定的URL,如果资源不存在,则创建它。
  4. doDelete(HttpServletRequest req, HttpServletResponse resp)
    • 处理 HTTP DELETE 请求。用来删除指定的资源。
  5. doHead(HttpServletRequest req, HttpServletResponse resp)
    • 处理 HTTP HEAD 请求。类似于 GET 请求,但只返回响应头,不返回响应体。
  6. doOptions(HttpServletRequest req, HttpServletResponse resp)
    • 处理 HTTP OPTIONS 请求。允许客户端查看目标资源支持的通信选项。
  7. doTrace(HttpServletRequest req, HttpServletResponse resp)
    • 处理 HTTP TRACE 请求。回显收到的请求,主要用于诊断。

通过继承 HttpServlet 抽象类,开发者可以获得对 HTTP 请求的更高级别的支持,而无需直接处理底层的 ServletRequestServletResponse 接口。这不仅简化了代码,也提高了开发效率。对于大多数 Web 应用程序来说,这是处理 HTTP 请求的标准方式。

servlet_413">自定义 servlet

如果要自定义 servlet,通常会继承 HttpServlet 类,然后重写 service()doGet() 和 doPost() 方法,比较推荐去重写 doGet() 和 doPost() 方法,因为父类 service() 可能会做了一些处理,如果我们重写的话,父类的方法就失效了。

如果 doGet()doPost() 方法体相同,可以在其中一个方法体里直接调用另一个方法。

在这里插入图片描述

ServletConfig 和 ServletContext

ServletConfig

ServletConfig 是一个接口,它提供了获取 servlet 初始化参数和 servlet 配置信息的方法。每个 servlet 实例在初始化时都会被赋予一个 ServletConfig 对象,通过这个对象,servlet 可以访问在部署描述符(如 web.xml)中为该 servlet 定义的初始化参数以及其他配置信息,每个 servlet 都有自己独立唯一的 ServletConfig 对象。

在这里插入图片描述

主要用途

  • 初始化参数:允许开发者为特定的 servlet 设置初始化参数,这些参数可以在 servlet 的整个生命周期内使用。
  • ServletContext 访问:提供了一种方式来访问 ServletContext,这使得 servlet 能够与整个 Web 应用进行交互,比如共享数据、获取资源路径等。

核心方法

以下是 ServletConfig 接口中定义的一些重要方法:

  1. getInitParameter(String name)
    • 返回指定名称的初始化参数值。如果不存在这样的参数,则返回 null
  2. getInitParameterNames()
    • 返回一个 Enumeration<String> 对象,包含所有初始化参数的名字。如果没有初始化参数,则返回空的枚举。
  3. getServletName()
    • 返回此 servlet 实例的名称,即在 web.xml<servlet-name> 元素所指定的名字或注解中指定的名字。
  4. getServletContext()
    • 返回代表当前上下文环境的 ServletContext 对象,通过它可以执行跨多个 servlet 共享的操作。

代码示例

下面是一个如何在自定义 servlet 中使用 ServletConfig 获取初始化参数的例子:

自定义 servlet

java">import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyServlet extends HttpServlet {private ServletConfig servletConfig;@Overridepublic void init(ServletConfig config) throws ServletException {super.init(config);this.servletConfig = config;}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取单个初始化参数String paramValue = servletConfig.getInitParameter("myParam");response.getWriter().println("Parameter value: " + paramValue);// 列出所有初始化参数Enumeration<String> parameterNames = servletConfig.getInitParameterNames();while (parameterNames.hasMoreElements()) {String paramName = parameterNames.nextElement();String paramValueAll = servletConfig.getInitParameter(paramName);response.getWriter().println("Parameter Name: " + paramName + ", Value: " + paramValueAll);}// 获取servlet名称String servletName = servletConfig.getServletName();response.getWriter().println("Servlet Name: " + servletName);}
}

为了使上述代码工作,你需要在 web.xml 文件中为你的 servlet 添加初始化参数:

web.xml

java"><servlet><servlet-name>MyServlet</servlet-name><servlet-class>com.example.MyServlet</servlet-class><init-param><param-name>myParam</param-name><param-value>valueForMyParam</param-value></init-param><init-param><param-name>anotherParam</param-name><param-value>valueForAnotherParam</param-value></init-param>
</servlet><servlet-mapping><servlet-name>MyServlet</servlet-name><url-pattern>/myservlet</url-pattern>
</servlet-mapping>

这样,当你访问 /myservlet 时,servlet 将能够读取并显示其初始化参数的值。使用 ServletConfig 接口可以让你更灵活地管理和使用 servlet 的初始化参数,同时也能更好地组织和维护你的 web 应用程序。

ServletContext

ServletContextservlet API 中的一个接口,代表了整个 Web 应用的上下文环境。每个 Java Web 应用程序在启动时都会创建一个 ServletContext 实例,这个实例在整个应用的生命周期内都可用,并且可以被该应用中的所有 servlet 共享。通过 ServletContextservlet 可以访问应用级别的配置信息、共享数据以及资源文件等。

总结:

  • ServletContext 对象有称呼为上下文对象,或者叫应用域对象。
  • 容器会为每个 app 创建一个独立的唯一的 ServletContext 对象。
  • ServletContext 对象为所有的 servlet 所共享。
  • ServletContext 可以为所有的 servlet 提供初始配置参数。

在这里插入图片描述

主要功能

  1. 共享数据:允许不同的 servlet 之间共享信息。
  2. 获取初始化参数:可以读取在 web.xml 或者注解中定义的应用级别初始化参数。
  3. 资源管理:能够获取应用内的资源文件(如配置文件)。
  4. 日志记录:提供基本的日志记录功能。
  5. 分发请求:支持请求转发和包含其他资源的功能。
  6. 属性操作:可以在 ServletContext 上设置、获取或移除属性,这些属性可以在整个Web应用范围内共享。

核心方法

以下是 ServletContext 接口中一些常用的方法:

  • getAttribute(String name)setAttribute(String name, Object object)
    • 获取和设置应用范围内的属性值。
  • getInitParameter(String name)getInitParameterNames()
    • 获取应用级别的初始化参数及其名称集合。
  • getContextPath()
    • 返回当前 Web 应用的上下文路径。
  • getResourceAsStream(String path)
    • 返回指定路径下的资源输入流,便于读取文件内容。
  • getRequestDispatcher(String path)
    • 返回一个 RequestDispatcher 对象,用于请求转发或包含其他资源。
  • log(String msg)log(String message, Throwable throwable)
    • 提供日志记录功能,前者记录简单消息,后者记录异常信息及堆栈跟踪。

代码示例

servlet

java">import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class ContextServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {ServletContext context = getServletContext();// 设置应用级属性context.setAttribute("appMessage", "Welcome to the application");// 获取应用级属性String appMessage = (String) context.getAttribute("appMessage");response.getWriter().println("Application Message: " + appMessage);// 获取初始化参数String initParam = context.getInitParameter("exampleParam");response.getWriter().println("Init Parameter: " + initParam);// 读取资源文件InputStream resourceStream = context.getResourceAsStream("/WEB-INF/config.properties");if (resourceStream != null) {response.getWriter().println("Resource loaded successfully.");} else {response.getWriter().println("Failed to load resource.");}}
}

web.xml:

<web-app><context-param><param-name>exampleParam</param-name><param-value>valueForExampleParam</param-value></context-param><servlet><servlet-name>contextServlet</servlet-name><servlet-class>com.example.ContextServlet</servlet-class></servlet><servlet-mapping><servlet-name>contextServlet</servlet-name><url-pattern>/contextServlet</url-pattern></servlet-mapping>
</web-app>

通过 ServletContext,你可以实现跨多个 servlet 的资源共享和通信,这对于构建复杂的 Web 应用程序非常有用。它不仅增强了不同组件之间的协作能力,还简化了对全局配置和资源的管理。

其他重要 API

获取资源的真实路径
java">String realPath = servletContext.getRealPath("资源在web目录中的路径");
  • 例如我们的目标是需要获取项目中某个静态资源的路径,不是工程目录中的路径,而是部署目录中的路径;我们如果直接拷贝其在我们电脑中的完整路径的话其实是有问题的,因为如果该项目以后部署到公司服务器上的话,路径肯定是会发生改变的,所以我们需要使用代码动态获取资源的真实路径。只要使用了 servletContext 动态获取资源的真实路径,那么无论项目的部署路径发生什么变化,都会动态获取项目运行时候的实际路径,所以就不会发生由于写死真实路径而导致项目部署位置改变引发的路径错误问题。
获取项目的上下文路径
java">String contextPath = servletContext.getContextPath();
  • 项目的部署名称,也叫项目的上下文路径,在部署进入 tomcat 时所使用的路径,该路径是可能发生变化的,通过该 API 动态获取项目真实的上下文路径,可以帮助我们解决一些后端页面渲染技术或者请求转发和响应重定向中的路径问题
域对象的相关API
  • 域对象:一些用于存储数据和传递数据的对象,传递数据不同的范围,我们称之为不同的域,不同的域对象代表不同的域,共享数据的范围也不同。
  • ServletContext 代表应用,所以 ServletContext 域也叫作应用域,是 webapp 中最大的域,可以在本应用内实现数据的共享和传递。
  • webapp 中的三大域对象,分别是应用域、会话域、请求域。
  • 三大域对象都具有的 API 如下:
API功能解释
void setAttribute(String key,Object value);向域中存储/修改数据
Object getAttribute(String key);获得域中的数据
void removeAttribute(String key);移除域中的数据

HttpServletRequest

HttpServletRequestservlet API 中的一个接口,它封装了客户端请求的所有信息。每当客户端向服务器发送一个请求时(例如通过点击链接、提交表单或输入 URL),Web 容器就会创建一个 HttpServletRequest 对象,并将其作为参数传递给被调用的 servletservice() 方法或者其特定的 doGet()doPost() 等方法。

  • HttpServletRequest 是一个接口,其父接口是 ServletRequest
  • HttpServletRequest 是 Tomcat 将请求报文转换封装而来的对象,在 Tomcat 调用 service() 方法时传入。
  • HttpServletRequest 代表客户端发来的请求,所有请求中的信息都可以通过该对象获得。

在这里插入图片描述

主要功能

  • 获取请求参数:可以从请求中提取查询字符串、表单数据等。
  • 获取请求头信息:允许访问所有 HTTP 请求头。
  • 会话管理:支持与客户端建立和维护会话。
  • 路径信息:提供关于请求 URL 的信息,包括上下文路径、Servlet 路径和路径信息。
  • Cookies:可以读取客户端发送的 cookie 信息。
  • 属性操作:可以在请求范围内设置、获取或移除属性,这些属性仅在当前请求有效。

核心方法

以下是 HttpServletRequest 接口中一些常用的方法:

  1. 请求参数
    • getParameter(String name):返回指定名称的第一个请求参数值。
    • getParameterValues(String name):当参数是多值(如复选框)时使用,返回一组值。
    • getParameterMap():返回请求参数的映射,其中键是参数名,值是对应的参数值数组。
  2. 请求头信息
    • getHeader(String name):获取指定名称的请求头值。
    • getHeaders(String name):返回指定名称的所有请求头值的枚举。
    • getHeaderNames():返回所有请求头名的枚举。
  3. 会话管理
    • getSession()getSession(boolean create):获取当前会话,如果不存在且 createtrue 则创建新会话。
  4. 路径信息
    • getContextPath():返回请求的上下文路径。
    • getRequestURI():返回请求行中的资源名称部分。
    • getQueryString():返回查询字符串(如果有)。
  5. Cookies
    • getCookies():返回所有发送到服务器的cookie对象的数组。
  6. 属性操作
    • setAttribute(String name, Object o):在请求范围内设置属性。
    • getAttribute(String name):获取请求范围内的属性值。
    • removeAttribute(String name):从请求中删除指定名称的属性。

代码示例

下面是一个简单的例子,展示了如何使用 HttpServletRequest 来处理表单提交的数据以及访问请求头信息:

java">import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebServlet("/formHandler")
public class FormHandlerServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取表单参数String username = request.getParameter("username");String password = request.getParameter("password");// 输出表单参数response.setContentType("text/html;charset=UTF-8");response.getWriter().println("<h1>Form Data</h1>");response.getWriter().println("Username: " + username + "<br>");response.getWriter().println("Password: " + password + "<br>");// 获取请求头信息String userAgent = request.getHeader("User-Agent");response.getWriter().println("User-Agent: " + userAgent + "<br>");// 获取Cookie信息Cookie[] cookies = request.getCookies();if (cookies != null) {for (Cookie cookie : cookies) {response.getWriter().println("Cookie Name: " + cookie.getName() + ", Value: " + cookie.getValue() + "<br>");}} else {response.getWriter().println("No cookies found.");}}
}

在这个例子中,我们创建了一个名为 FormHandlerServletservlet,它处理 POST 请求并展示如何从请求中提取表单数据、请求头信息以及 cookie 数据。这展示了 HttpServletRequest 在处理客户端请求时的强大功能。通过利用 HttpServletRequest 提供的各种方法,开发者可以方便地访问和处理来自客户端的所有相关信息。

HttpServletResponse

HttpServletResponse 是 Servlet API 中的一个接口,它代表了服务器对客户端请求的响应。通过 HttpServletResponse 对象,servlet 可以向客户端发送响应数据,包括设置响应头、状态码以及输出响应内容等。

  • HttpServletResponse 是一个接口,其父接口是 ServletResponse
  • HttpServletResponse 是 Tomcat 预先创建的,在 Tomcat 调用 service() 方法时传入。
  • HttpServletResponse 代表对客户端的响应,该对象会被转换成响应的报文发送给客户端,通过该对象我们可以设置响应信息。

在这里插入图片描述

主要功能

  • 发送响应数据:可以通过 PrintWriterOutputStream 向客户端发送文本或二进制数据。
  • 设置响应头:可以设置各种 HTTP 响应头,如内容类型、缓存控制等。
  • 重定向:支持将请求重定向到另一个资源。
  • 错误处理:允许发送错误状态码和自定义错误页面。
  • 会话管理:可以通过 cookie 来维护与客户端的会话状态。

核心方法

以下是 HttpServletResponse 接口中一些常用的方法:

  1. 发送响应数据
    • getWriter():返回一个 PrintWriter 对象,用于发送字符文本响应。
    • getOutputStream():返回一个 ServletOutputStream 对象,用于发送二进制数据。
  2. 设置响应头
    • setContentType(String type):设置响应的内容类型(如 text/html, application/json)。
    • addHeader(String name, String value):添加一个响应头。
    • setHeader(String name, String value):设置一个响应头,如果该响应头已存在,则覆盖原有的值。
  3. 重定向
    • sendRedirect(String location):将客户端重定向到另一个资源(URL)。这会导致浏览器发出一个新的请求。
  4. 错误处理
    • setStatus(int sc):设置整数状态码。
    • sendError(int sc)sendError(int sc, String msg):发送指定的状态码及可选的消息给客户端,并自动使用适当的错误页面。
  5. 会话管理
    • addCookie(Cookie cookie):向客户端添加一个新的 cookie。

代码示例

下面是一个简单的例子,展示了如何使用 HttpServletResponse 发送文本响应、设置响应头以及执行重定向:

java">import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebServlet("/responseDemo")
public class ResponseDemoServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 设置响应内容类型response.setContentType("text/html;charset=UTF-8");// 发送文本响应response.getWriter().println("<h1>Hello from HttpServletResponse</h1>");// 添加响应头response.setHeader("MyCustomHeader", "HeaderValue");// 设置cookieCookie userCookie = new Cookie("username", "john_doe");userCookie.setMaxAge(60*60); // 有效期为一小时response.addCookie(userCookie);// 执行重定向// response.sendRedirect("http://example.com");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 处理POST请求doGet(request, response);}
}

在这个例子中,我们创建了一个名为 ResponseDemoServletservlet,它演示了如何使用 HttpServletResponse 设置响应的内容类型、发送文本响应、设置自定义响应头、添加 cookie 以及如何进行重定向(注释部分)。这些功能使得 HttpServletResponse 成为了与客户端通信的关键组件之一,允许开发者灵活地控制响应的各种方面。

请求转发和响应重定向

请求转发和响应重定向是 Web 开发中两种不同的机制,用于处理客户端请求并将用户导航到另一个资源。

  • 请求转发和响应重定向是 web 应用中间接访问项目资源的两种手段,也是 Servlet 控制页面跳转的两种手段。

  • 请求转发通过 HttpServletRequest 实现,响应重定向通过 HttpServletResponse 实现。

  • 请求转发生活举例:张三找李四借钱,李四没有,李四找王五,让王五借给张三。

  • 响应重定向生活举例:张三找李四借钱,李四没有,李四让张三去找王五,张三自己再去找王五借钱。

请求转发

  • 请求转发通过 HttpServletRequest 对象获取请求转发器实现。
  • 请求转发是服务器内部的行为,对客户端是屏蔽的。
  • 客户端只发送了一次请求,客户端地址栏不变。
  • 服务端只产生了一对请求和响应对象,这一对请求和响应对象会继续传递给下一个资源。
  • 因为全程只有一个 HttpServletRequset 对象,所以请求参数可以传递,请求域中的数据也可以传递。
  • 请求转发可以转发给其他 Servlet 动态资源,也可以转发给一些静态资源以实现页面跳转。
  • 请求转发可以转发给 WEB-INF 下受保护的资源。
  • 请求转发不能转发到本项目以外的外部资源。

在这里插入图片描述

代码示例

java">import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebServlet("/original")
public class OriginalServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 添加请求属性request.setAttribute("message", "This is a forwarded message");// 获取RequestDispatcher并转发请求RequestDispatcher dispatcher = request.getRequestDispatcher("/target.jsp");dispatcher.forward(request, response);}
}

在这个例子中,OriginalServlet 接收请求后,添加了一个名为 message 的请求属性,并将其转发给 target.jsp 页面。这样,target.jsp 就可以访问这个属性并显示相应的消息。

响应重定向

  • 响应重定向通过 HttpServletResponse 对象的 sendRedirect() 方法实现。
  • 响应重定向是服务端通过302响应码和路径,告诉客户端自己去找其他资源,是在服务端提示下的,客户端的行为。
  • 客户端至少发送了两次请求,客户端地址栏是要变化的。
  • 服务端产生了多对请求和响应对象,且请求和响应对象不会传递给下一个资源。
  • 因为全程产生了多个 HttpServletRequset 对象,所以请求参数不可以传递,请求域中的数据也不可以传递。
  • 重定向可以是其他 Servlet 动态资源,也可以是一些静态资源以实现页面跳转。
  • 重定向不可以到给 WEB-INF 下受保护的资源。
  • 重定向可以到本项目以外的外部资源。

在这里插入图片描述

代码示例

java">import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebServlet("/redirectDemo")
public class RedirectDemoServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 执行某些业务逻辑// 发送重定向响应response.sendRedirect("http://example.com");// 或者相对路径// response.sendRedirect("/newPage.jsp");}
}

在这个例子中,当用户访问 /redirectDemo 路径时,Servlet会执行一些业务逻辑,然后通过 sendRedirect() 方法告诉客户端去访问 http://example.com 或者应用内部的 /newPage.jsp 页面。

MVC 架构模式

MVC(Model-View-Controller,模型-视图-控制器)是软件工程中的一种软件架构模式,它把软件系统分为模型视图控制器三个基本部分。用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

模型(Model)

  • 职责:负责处理应用的数据逻辑,即与数据库或数据源交互的部分。模型直接管理应用程序的数据域,并通知视图任何状态的变化,以及接收来自控制器的输入。
  • 特点
    • 数据库操作(如 CRUD 操作)。
    • 业务逻辑和规则的实现。
    • 状态管理和数据验证。
  • 功能
    • 存放和数据库对象的实体类以及一些用于存储非数据库表完整相关的 VO 对象。
    • 存放一些对数据进行逻辑运算操作的的一些业务处理代码。

视图(View)

  • 职责:负责展示数据,即用户界面部分。视图从模型中获取数据并决定如何显示这些数据给用户。同时,它也会接收用户的输入并将这些输入转发给控制器。
  • 特点
    • 用户界面的设计与实现。
    • 显示数据并允许用户与其交互。
    • 可以有多个视图对应同一个模型,提供不同的展示方式。
  • 功能
    • 存放一些视图文件相关的代码 html、css、js 等。
    • 在前后端分离的项目中,后端已经没有视图文件,该层次已经衍化成独立的前端项目。

控制器(Controller)

  • 职责:作为模型和视图之间的协调者,控制器接收用户的输入,调用模型的方法更新数据或状态,并选择合适的视图来呈现修改后的模型状态。
  • 特点
    • 处理用户输入并将其转换为命令发送给模型或视图。
    • 决定哪个视图应该被用来响应用户请求。
    • 可能包含复杂的业务逻辑来决定如何处理特定的输入。
  • 功能
    • 接收客户端请求,获得请求数据。
    • 将准备好的数据响应给客户端。

MVC 模式下,项目中的常见包

  • M:

    • 实体类包(pojo、entity、bean)专门存放和数据库对应的实体类和一些 VO 对象。
    • 数据库访问包(dao、mapper)专门存放对数据库不同表格 CURD 方法封装的一些类。
    • 服务包(service)专门存放对数据进行业务逻辑运算的一些类。
  • C:

    • 控制层包(controller)。
  • V:

    • web目录下的视图资源 html、css、js、img 等。
    • 前端工程化后,在后端项目中已经不存在了。

非前后端分离的 MVC

在这里插入图片描述

前后端分离的 MVC

在这里插入图片描述


http://www.ppmy.cn/news/1577889.html

相关文章

一周热点-文本生成中的扩散模型- Mercury Coder

一、背景知识 在人工智能领域&#xff0c;文本生成模型一直是研究的热点。传统的大型语言模型多采用自回归架构&#xff0c;从左到右逐个预测下一个标记。这种模型虽然在生成连贯文本方面表现出色&#xff0c;但在速度上存在一定的局限性&#xff0c;因为它需要按顺序生成每个标…

C/C++蓝桥杯算法真题打卡(Day4)

一、P11041 [蓝桥杯 2024 省 Java B] 报数游戏 - 洛谷 算法代码&#xff1a; #include<bits/stdc.h> using namespace std;// 计算第 n 个满足条件的数 long long findNthNumber(long long n) {long long low 1, high 1e18; // 二分查找范围while (low < high) {lo…

使用ASIWebPageRequest库编写Objective-C下载器程序

使用 ASIWebPageRequest 库编写 Objective-C 下载器程序是一个简单且高效的方式来处理 HTTP 请求。在 ASIHTTPRequest 和 ASIWebPageRequest 中&#xff0c;ASIWebPageRequest 是专门用于下载网页及其资源的库。 1. 安装 ASIWebPageRequest 首先&#xff0c;你需要安装 ASIHT…

linux 设置tomcat开机启动

在Linux系统中&#xff0c;要配置Tomcat开机自启动&#xff0c;可以创建一个名为 tomcat.service 的 systemd 服务文件&#xff0c;并将其放置在 /etc/systemd/system/ 目录下。以下是一个基本的服务文件示例&#xff0c;假设Tomcat安装在 /usr/local/tomcat 路径下&#xff1a…

雷池WAF的为什么选择基于Docker

Docker 是一种开源的容器化平台&#xff0c;可以帮助开发人员将应用程序及其所有依赖项打包到一个称为容器的独立、可移植的环境中。Docker 的核心概念包括以下几点&#xff1a; 容器&#xff1a;Docker 使用容器来封装应用程序及其依赖项&#xff0c;使其能够在任何环境中都能…

如何确保爬虫遵守1688的使用协议

在使用爬虫技术调用1688开放平台的API接口时&#xff0c;确保爬虫遵守平台的使用协议至关重要。这不仅有助于避免法律风险&#xff0c;还能确保数据获取行为的合规性和道德性。以下是确保爬虫遵守1688使用协议的具体方法和注意事项&#xff1a; 一、遵守法律法规 合法使用数据…

后 Safe 时代:多签钱包安全新范式与防范前端攻击的新思路

时间轴 2025 年 2 月 21 日&#xff1a;Bybit 多签钱包被攻击&#xff0c;15 亿美金通过「合法」签名交易流出。 链上追踪&#xff1a;资金转入匿名地址并分拆混币&#xff0c;攻击者与部分验证节点存在潜在关联。 事后分析&#xff1a;安全审计发现攻击者利用 Safe 前端的供…

深入理解Tomcat的Request复用机制及其风险

深入理解Tomcat的Request复用机制及其风险 前言一、什么是Request复用机制&#xff1f;二、Request复用的好处三、Request复用的风险四、如何优化Request复用的机制&#xff1f;总结 前言 在高并发的Web应用中&#xff0c;性能优化是每个开发者需要关注的核心问题之一。为了提…