JAVAWeb之Servlet学习

news/2025/2/23 22:30:03

认识

Servlet 就是 Sun 公司开发动态 Web 的一门技术

Sun 在这些 API (Application Programming Interface,应用程序接口)中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:

  • 编写一个类,实现Servlet接口。
  • 把开发好的Java类部署到web服务器中。

把实现了 Servlet 接口的 Java 程序叫做,Servlet

广义的 Servlet

广义的 Servlet 不仅仅指的是实现了 Servlet 接口的 Java 类,还包括与 Servlet 相关的一系列技术和组件,如 Servlet 容器、过滤器(Filter)、监听器(Listener)等,它们共同构成了 Java Web 应用的基础架构。

狭义的 Servlet

狭义的 Servlet 指的是遵循 Servlet 规范编写的 Java 类,这些类实现了 javax.servlet.Servlet 接口或继承自 javax.servlet.GenericServletjavax.servlet.http.HttpServlet 等抽象类。它们用于处理客户端的 HTTP 请求,并生成相应的响应。

生命周期

Servlet 的生命周期包括以下几个阶段:

  1. 加载和实例化:当客户端第一次请求某个 Servlet 时,Web 服务器会加载该 Servlet 类并创建其实例。
  2. 初始化:Servlet 实例创建后,服务器会调用其 init 方法进行初始化操作。init 方法在 Servlet 的整个生命周期中只会被调用一次。
  3. 服务:当客户端发送请求时,服务器会调用 Servlet 的 service 方法。service 方法会根据请求的类型(如 GET、POST)调用相应的 doGetdoPost 方法来处理请求。
  4. 销毁:当 Web 服务器关闭或 Servlet 被卸载时,服务器会调用 Servlet 的 destroy 方法进行资源释放和清理工作。

工作原理

概述

  1. 客户端发起请求:客户端(如浏览器)通过 HTTP 协议向 Web 服务器发送请求。
  2. 服务器接收请求:Web 服务器(如 Tomcat)接收到请求后,根据请求的 URL 查找对应的 Servlet。
  3. 调用 Servlet:如果找到对应的 Servlet,服务器会创建或复用 Servlet 实例,并调用其相应的方法(如 doGetdoPost)来处理请求。
  4. Servlet 处理请求:Servlet 方法根据请求的信息进行相应的处理,如读取请求参数、访问数据库等。
  5. 生成响应:Servlet 处理完请求后,生成响应数据,如 HTML 页面、JSON 数据等,并将其发送回客户端。
  6. 服务器返回响应:Web 服务器将 Servlet 生成的响应发送给客户端。

在 Maven Web 项目中,当你启动项目后,会生成一个target的目录。 target 包是 Maven 构建过程中产生的输出目录,主要包含以下内容:

  • 编译后的类文件:项目中所有 Java 源文件(如 src/main/java 目录下的 BasicServlet 等类文件)**经过编译后生成的 .class 文件,**会被放置在 target/classes 目录及其子目录中,这些字节码文件是程序运行时 JVM 可执行的文件。
  • 资源文件:src/main/resources 目录下的资源文件,在构建过程中会被复制到 target/classes 目录中,比如配置文件等,方便运行时程序读取。
  • 打包后的文件:如果对项目进行打包操作(如执行 mvn package 命令),会生成如 WAR 包(Web 应用归档文件)等,也会存放在 target 目录下。这些包可以直接部署到 Tomcat 等 Web 服务器上运行。
  • 生成的辅助文件:像 generated-sources 目录下存放的由 Maven 插件生成的一些源文件,例如注解处理生成的文件等 ,用于辅助项目的编译和运行。

target 包对于项目的编译、运行、部署都至关重要,是项目从源码到可执行或可部署状态的中间产物集合。

target和Servlet 生命周期

target/classes 下的文件与 Servlet 的生命周期密切相关。

1. 加载和实例化阶段

在 Web 应用启动时,Web 服务器(如 Tomcat)会去 target/classes 目录及其子目录中查找 Servlet 类的字节码文件(.class 文件)。例如图中的 BasicServletRedirectServletSubmitForm 等 Servlet 类,编译后的字节码文件就存放在该目录对应的包结构下。服务器加载这些字节码文件,并通过类加载机制将其加载到 JVM 中,然后创建 Servlet 实例(上文提到过,当你第一次访问时才会创建servlet实例,并且每个servlet只有一个实例),这个过程依赖于 target/classes 下正确的字节码文件,没有它们,服务器无法识别和实例化 Servlet。

2. 初始化阶段

Servlet 实例创建后,服务器会调用其 init 方法进行初始化init 方法中可能会读取配置文件等资源,而这些配置文件如果在项目开发阶段放在 src/main/resources 目录下,在构建过程中会被复制到 target/classes 目录中,Servlet 可以从这里读取所需信息来完成初始化,因此 target/classes 下的资源文件对于 Servlet 初始化过程必不可少。

Servlet :

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

    ServletConfig getServletConfig();

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

    String getServletInfo();

    void destroy();
}

GenericServlet:

public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
}
初始化信息

ServletConfig 是一个由 Servlet 容器(如 Tomcat)创建并传递给 Servlet 的对象,它包含了 Servlet 的配置信息。包含的配置信息如下:

  • Servlet 名称
  • 初始化参数<init-param>
  • ServletContext

Servlet 名称

  • 获取方法:通过 getServletName() 方法获取。
  • 配置方式:在部署描述符(如 web.xml)中使用 <servlet-name> 标签进行配置;若使用注解方式(如 @WebServlet),则由注解中的 name 属性指定。
//--------------**web.xml 配置**:-----------------
<servlet>
    <servlet-name>MySampleServlet</servlet-name>
    <servlet-class>com.example.MyServlet</servlet-class>
</servlet>

//--------------**注解方式**:-----------------
@WebServlet(name = "MySampleServlet", urlPatterns = "/myServlet")
public class MyServlet extends HttpServlet {
    // Servlet 实现代码
}

初始化参数

  • 获取方法
    • 通过 getInitParameter(String name) 方法获取指定名称的初始化参数值。
    • 通过 getInitParameterNames() 方法获取所有初始化参数的名称枚举。
  • 配置方式:在 web.xml 中使用 <init-param> 标签进行配置;若使用注解方式,可在 @WebServlet 注解中使用 initParams 属性指定。
//--------------**web.xml 配置**:-----------------
<servlet>
    <servlet-name>MySampleServlet</servlet-name>
    <servlet-class>com.example.MyServlet</servlet-class>
    <init-param>
        <param-name>dbUrl</param-name>
        <param-value>jdbc:mysql://localhost:3306/mydb</param-value>
    </init-param>
    <init-param>
        <param-name>dbUser</param-name>
        <param-value>root</param-value>
    </init-param>
</servlet>
//--------------**注解方式**:-----------------
@WebServlet(name = "MySampleServlet", urlPatterns = "/myServlet", 
            initParams = {
                @WebInitParam(name = "dbUrl", value = "jdbc:mysql://localhost:3306/mydb"),
                @WebInitParam(name = "dbUser", value = "root")
            })
public class MyServlet extends HttpServlet {
    // Servlet 实现代码
}

ServletContext 对象

  • 获取方法:通过 getServletContext() 方法获取。
  • 配置方式:由 Servlet 容器自动创建和管理,无需开发者手动配置。

3. 服务阶段

当客户端发送请求时,服务器根据请求的 URL 找到对应的 Servlet 实例,并调用其 service 方法,进而根据请求类型(如 GETPOST)调用 doGetdoPost 等方法处理请求。在处理请求过程中,Servlet 可能会调用其他类、访问数据库等,这些相关类的字节码文件同样存放在 target/classes 目录下,只有该目录下的类文件完整且正确,Servlet 才能正常执行服务逻辑。

4. 销毁阶段

当 Web 应用停止或服务器关闭时,Servlet 的 destroy 方法会被调用以释放资源。destroy 方法执行过程中,也可能依赖于 target/classes 目录下的一些配置信息来完成资源清理等操作,例如关闭与特定配置相关的连接等。

target/classes 下的文件是 Servlet 生命周期各个阶段能够正常运行的基础,包含了 Servlet 类及其依赖类的字节码文件以及相关资源文件等关键内容。

web.xml

常见配置元素

1. Servlet 配置

<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.example.MyServlet</servlet-class>
    <init-param>
        <param-name>param1</param-name>
        <param-value>value1</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/myServlet</url-pattern>
</servlet-mapping>
  • <servlet>:定义一个 Servlet,包含 Servlet 的名称和对应的 Java 类。
  • <servlet-name>:为 Servlet 命名,用于在其他配置中引用。
  • <servlet-class>:指定 Servlet 类的全限定名。
  • <init-param>:为 Servlet 设置初始化参数。
  • <load-on-startup>:指定 Servlet 的加载顺序,数值越小越先加载。
  • <servlet-mapping>:将 Servlet 映射到一个或多个 URL 模式。

2. 过滤器配置

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.example.MyFilter</filter-class>
    <init-param>
        <param-name>filterParam</param-name>
        <param-value>filterValue</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • <filter>:定义一个过滤器,包含过滤器的名称和对应的 Java 类。
  • <filter-name>:为过滤器命名。
  • <filter-class>:指定过滤器类的全限定名。
  • <init-param>:为过滤器设置初始化参数。
  • <filter-mapping>:将过滤器映射到一个或多个 URL 模式。

3. 监听器配置

<listener>
    <listener-class>com.example.MyListener</listener-class>
</listener>
  • <listener>:注册一个监听器,指定监听器类的全限定名。

4. 全局初始化参数

<context-param>
    <param-name>globalParam</param-name>
    <param-value>globalValue</param-value>
</context-param>
  • <context-param>:设置整个 Web 应用的初始化参数。

5. 错误页面配置

<error-page>
    <error-code>404</error-code>
    <location>/404.jsp</location>
</error-page>
<error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/error.jsp</location>
</error-page>
  • <error-page>:指定不同 HTTP 错误状态码或异常类型对应的错误处理页面。

示例 web.xml 文件

<?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">

    <!-- 全局初始化参数 -->
    <context-param>
        <param-name>globalParam</param-name>
        <param-value>globalValue</param-value>
    </context-param>

    <!-- Servlet 配置 -->
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.example.MyServlet</servlet-class>
        <init-param>
            <param-name>param1</param-name>
            <param-value>value1</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/myServlet</url-pattern>
    </servlet-mapping>

    <!-- 过滤器配置 -->
    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.example.MyFilter</filter-class>
        <init-param>
            <param-name>filterParam</param-name>
            <param-value>filterValue</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 监听器配置 -->
    <listener>
        <listener-class>com.example.MyListener</listener-class>
    </listener>

    <!-- 错误页面配置 -->
    <error-page>
        <error-code>404</error-code>
        <location>/404.jsp</location>
    </error-page>
    <error-page>
        <exception-type>java.lang.Exception</exception-type>
        <location>/error.jsp</location>
    </error-page>
</web-app>

与注解的对比

从 Servlet 3.0 开始,Java 支持使用注解(如 @WebServlet@WebFilter@WebListener 等)来替代部分 web.xml 的配置。注解的优点是代码更加简洁,配置与代码紧密结合;而 web.xml 的优点是配置集中,便于统一管理和维护,对于复杂的配置场景更为合适。在实际开发中,也可以将注解和 web.xml 结合使用。

ServletContext

ServletContext 是 Java Servlet 规范中的一个重要接口,代表整个 Web 应用程序,在 Web 应用的生命周期内只有一个 ServletContext 实例。

获取方式

在 Servlet 中,可以通过以下两种常见方式获取 ServletContext 对象:

  • 通过 ServletConfig 获取:重写init()方法。在 Servlet 的 init(ServletConfig config) 方法中,可以通过 config.getServletContext() 方法获取 ServletContext 对象。示例代码如下:
  • 直接获取:在 Servlet 中,也可以直接通过 getServletContext() 方法获取 ServletContext 对象。
public class MyServlet extends HttpServlet {
    private ServletContext context;

    //重写init()方法即可
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        context = config.getServletContext();
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = getServletContext();
    }
}

常用方法

  • 存储和获取属性
    • void setAttribute(String name, Object object):将一个对象存储在 ServletContext 中,使用指定的名称作为键。
    • Object getAttribute(String name):根据指定的名称从 ServletContext 中获取存储的对象,如果对象不存在则返回 null
    • void removeAttribute(String name):从 ServletContext 中移除指定名称的属性。
  • 读取资源文件
    • java.io.InputStream getResourceAsStream(String path):返回指定路径下资源文件的输入流,用于读取文件内容。
    • java.net.URL getResource(String path):返回指定路径下资源文件的 URL。
  • 获取初始化参数
    • String getInitParameter(String name):返回指定名称的应用初始化参数的值,如果参数不存在则返回 null
    • java.util.Enumeration<String> getInitParameterNames():返回所有应用初始化参数名称的枚举。
  • 请求转发
    • getRequestDispatcher(String path)

此外还有:

  • 日志记录:log()
  • 获取上下文路径:String getContextPath()
--------------------存储和获取属性----------------------
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("Hello Servlet");

        ServletContext context = this.getServletContext();

        context.setAttribute("msg", "Hello Servlet");
    }
}

public class ReadContextServelt extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = (String) this.getServletContext().getAttribute("msg");
        System.out.println(msg);
        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().print("ReadContextServlet"+ msg);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
------------------读取资源文件-----------------------
public class TwoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/dp.properties");
        Properties properties = new Properties();
        properties.load(is);
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");
        resp.getWriter().print("username:"+username+" password:"+password);
    }
}
-----------------获取初始化参数-------------------
public class GetParamServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        String username = context.getInitParameter("user");
        String password = context.getInitParameter("password");
        resp.getWriter().write("username:"+username+" password:"+password);
    }

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

    <context-param>
        <param-name>user</param-name>
        <param-value>root</param-value>
    </context-param>
    <context-param>
        <param-name>password</param-name>
        <param-value>123456</param-value>
    </context-param>
-------------------------请求转发---------------------
public class SourceServletWithContext extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取 ServletContext 对象
        ServletContext context = getServletContext();

        // 通过 ServletContext 获取 RequestDispatcher 对象
        RequestDispatcher dispatcher = context.getRequestDispatcher("/targetServlet");

        // 执行转发操作
        dispatcher.forward(request, response);
    }
}
public class TargetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().println("<html><body>");
        response.getWriter().println("<h2>这是目标 Servlet 处理的结果</h2>");
        response.getWriter().println("</body></html>");
    }
}

HttpServletResponse

功能概述

  • 设置响应状态码:告知客户端请求的处理结果,如 200 表示请求成功,404 表示请求的资源不存在,500 表示服务器内部错误等。
  • 设置响应头:可以设置各种 HTTP 响应头信息,如内容类型、缓存控制、字符编码等,用于控制客户端对响应的处理方式。
  • 输出响应体:向客户端发送实际的响应内容,如 HTML 页面、JSON 数据、图片等。

常用方法

1. 设置响应状态码

在这里插入图片描述

  • setStatus(int sc):设置 HTTP 响应的状态码。例如,response.setStatus(HttpServletResponse.SC_OK) 表示请求成功,状态码为 200。
  • sendError(int sc):发送错误响应给客户端,同时设置相应的错误状态码。例如,response.sendError(HttpServletResponse.SC_NOT_FOUND) 表示请求的资源不存在,状态码为 404。

2. 设置响应头

  • setHeader(String name, String value):设置指定名称的响应头及其值。例如,response.setHeader("Content-Type", "text/html;charset=UTF-8") 用于设置响应内容的类型为 HTML,并指定字符编码为 UTF-8。
  • addHeader(String name, String value):添加一个响应头,如果该名称的响应头已经存在,则会添加一个新的值。
  • setContentType(String type):设置响应内容的类型。例如,response.setContentType("application/json") 表示响应内容为 JSON 数据。
  • setCharacterEncoding(String charset):设置响应的字符编码。例如,response.setCharacterEncoding("UTF-8") 用于指定响应使用 UTF-8 编码。

3. 输出响应体

  • getWriter():返回一个 PrintWriter 对象,用于以字符流的方式输出响应内容。通常用于输出文本数据,如 HTML 页面、JSON 字符串等。
  • getOutputStream():返回一个 ServletOutputStream 对象,用于以字节流的方式输出响应内容。通常用于输出二进制数据,如图片、文件等。

代码示例

public class SendErrorExampleServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendError(404, "404 Not Found");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
public class SetStatusExampleServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        resp.setStatus(666);
        resp.setStatus(200);
        resp.getWriter().write("更改状态响应码");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

实现重定向

public class RedirctServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        log("RedirctServlet");
        resp.sendRedirect("/r/basic");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
public class BasicServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("basic");
    }

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

HttpServletRequest

HttpServletRequest 是 Java Servlet 规范中的一个重要接口,它封装了客户端发送的 HTTP 请求信息。Servlet 可以通过 HttpServletRequest 对象获取客户端请求的各种信息,如请求参数、请求头、请求方法等,从而根据这些信息进行相应的处理。以下从功能、常用方法、使用示例等方面详细介绍。

功能概述

  • 获取请求参数:客户端在发送请求时,可能会携带一些参数,如表单数据、URL 参数等。HttpServletRequest 提供了方法来获取这些参数的值。
  • 获取请求头信息:HTTP 请求包含多个请求头,如 User - AgentCookie 等。通过 HttpServletRequest 可以获取这些请求头的信息。
  • 获取请求方法:确定客户端发送请求所使用的方法,如 GETPOST 等。
  • 获取请求的 URL 和 URI:获取客户端请求的完整 URL 或相对 URI,用于处理请求路径相关的逻辑。
  • 获取会话信息:通过 HttpServletRequest 可以获取或创建用户的会话(HttpSession),用于在多个请求之间共享数据。

获取请求参数代码演示

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>表单提交示例</title>
</head>
<body>
<form action="submitForm" method="post">
  <!-- 普通文本输入框,对应单个值的参数 -->
  <label for="username">用户名:</label>
  <input type="text" id="username" name="username"><br>

  <!-- 显示爱好标签 -->
  <span>爱好:</span><br>
  <!-- 多选框,对应多个值的参数 -->
  <input type="checkbox" id="reading" name="hobbies" value="阅读">
  <label for="reading">阅读</label><br>
  <input type="checkbox" id="sports" name="hobbies" value="运动">
  <label for="sports">运动</label><br>
  <input type="checkbox" id="music" name="hobbies" value="音乐">
  <label for="music">音乐</label><br>

  <input type="submit" value="提交">
</form>
</body>
</html>

public class SubmitForm extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 设置响应内容类型和字符编码
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();

        // 使用 getParameter 方法获取单个值的参数
        String username = req.getParameter("username");
        out.write(username);

        // 使用 getParameterValues 方法获取多个值的参数
        String[] hobbies = req.getParameterValues("hobbies");
        if (hobbies != null) {
            for (String hobby : hobbies) {
                out.println("<p>" + hobby + "</p>");
            }
        }
    }

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

补充

ServletContext与 ServletRequest 获取 RequestDispatcher 的区别

  • ServletRequest.getRequestDispatcher:路径是相对于当前请求的路径。例如,如果当前请求的 URL 是 /app/someServlet,调用 request.getRequestDispatcher("anotherServlet") 会将请求转发到 /app/anotherServlet
  • ServletContext.getRequestDispatcher:路径是相对于 Web 应用的根目录。例如,context.getRequestDispatcher("/anotherServlet") 会将请求转发到 Web 应用根目录下的 anotherServlet

转发和重定向

在 Java Web 开发中,转发(Forward)和重定向(Redirect)是两种常用的页面跳转方式,它们都能实现从一个资源跳转到另一个资源,但在多个方面存在明显区别。

转发是服务器端的行为。当客户端发送请求到服务器的某个 Servlet 或 JSP 页面时,如果该资源无法完全处理请求,或者需要其他资源协助处理,服务器会直接将请求转发给另一个 Servlet、JSP 页面或静态资源,整个过程都在服务器内部完成,客户端并不知道请求发生了转发。

重定向:是客户端的行为(重新定义方向,换页面,全换)。服务器接收到客户端的请求后,会返回一个重定向响应(状态码 302 或 303)给客户端,其中包含了新的 URL 地址。客户端收到这个响应后,会自动向新的 URL 地址发送一个新的请求。

  • 转发:整个过程只涉及一次请求。url不会变化

  • 重定向:涉及两次请求。url变化

  • 转发示例代码与说明

在一个大型的用户管理系统中,用户注册功能涉及多个步骤**,如输入验证、数据插入数据库、发送注册成功邮件等**。为了提高代码的可维护性和复用性,可以将这些步骤拆分成不同的 Servlet 来处理,通过转发实现模块之间的协作。在整个用户注册流程中,如果只是在服务器端的不同 Servlet 之间进行转发处理,且没有返回新的页面内容给客户端,前端页面从用户的视觉上看不会发生变化。例如,在输入验证、数据插入数据库、发送注册成功邮件这些步骤中,服务器端的 Servlet 依次处理请求,期间只是在内部传递数据和执行逻辑,没有给客户端返回新的 HTML 页面。

// 处理用户注册表单提交的 Servlet
@WebServlet("/registerForm")
public class RegisterFormServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //......
        dispatcher.forward(request, response);
    }
}

// 处理数据插入的 Servlet
@WebServlet("/insertUserServlet")
public class InsertUserServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // 实际应用中这里会有数据库插入代码
        System.out.println("用户 " + username + " 已成功插入数据库");
        
        dispatcher.forward(request, response);
    }
}

// 发送注册成功邮件的 Servlet
@WebServlet("/sendEmailServlet")
public class SendEmailServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 模拟发送邮件操作
        System.out.println("已向用户 " + username + " 发送注册成功邮件");
        
        response.getWriter().write("注册成功");
    }
}

在这个示例中,从 RegisterFormServlet 开始,依次转发到 insertUserServletsendEmailServlet 进行处理,最后只是返回了一个简单的文本信息 “注册成功”,前端页面在视觉上不会有明显变化,除非页面上有 JavaScript 代码监听服务器响应并进行相应的页面更新。


http://www.niftyadmin.cn/n/5863828.html

相关文章

多门店协同管理困难重重,管理系统如何破局?

在零售业的快速发展中&#xff0c;越来越多的企业选择通过多门店的方式扩展市场。然而&#xff0c;随着门店数量的增加&#xff0c;企业在日常运营中的管理难度也逐渐加大&#xff0c;尤其是在协调各个门店之间的资源、信息和流程时&#xff0c;往往面临诸多挑战。如何在多门店…

Windows逆向工程入门之结构体类特性分析

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 基本特性 构造函数 静态成员 常量成员 继承构造 继承(单) 继承(多) 继承(菱) 多态(单) 多态(多) 虚表(单) 虚表(多) 纯虚 基本特性 #include <iostream> #include &l…

红队内网攻防渗透:内网渗透之内网对抗:实战项目VPC1打靶PHP-RCE三层代理路由防火墙上线密码喷射域控提权

红队内网攻防渗透 实战网络攻防靶场记录1.靶机配置详情讲解1.1 入口点靶机:Windows Server 20121.2 第一层靶机:Windows 7 + Windows 101.3 第二层靶机:Windows 2012 R21.4 第三层靶机:Windows 2016 web +Windows 2016 AD域1.5 攻击者系统 :Kali-linux2.靶场渗透完整流程2…

算法-栈和队列篇04-滑动窗口最大值

滑动窗口最大值 力扣题目链接 题目描述 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 解题思路 这道题目一开始我是直…

Orcale、MySQL中参数类型的详解和运用场景(带示例)

Oracle 中的参数类型及运用场景 1. 数值类型 NUMBER(p, s) 详解&#xff1a;p 表示精度&#xff08;即数字的总位数&#xff09;&#xff0c;s 表示小数位数。例如&#xff0c;NUMBER(5, 2) 可以存储最大为 999.99 的数字。运用场景&#xff1a;适用于需要精确计算的财务数据…

docker基操

docker基操 首先就是安装docker使用docker:创建容器-制作一个镜像-加载镜像首先就是安装docker 随便找一个教程安装就可以,安装过程中主要是不能访问谷歌,下面这篇文章写了镜像的一些问题: 安装docker的网络问题 使用docker:创建容器-制作一个镜像-加载镜像 主要是参考:这篇…

【数字图像处理二】图像增强与空域处理

1. 图像增强的目的 图像增强的目的是通过各种处理方法改善图像的视觉效果&#xff0c;旨在满足特定应用场合的需求。其核心目的是增强图像的整体或局部特性。通过图像增强&#xff0c;我们能够将原本模糊的图像变得更加清晰&#xff0c;突出某些感兴趣的特征&#xff0c;扩大图…

一个解析cyber record文件的python示例脚本

Cyber RT 是百度开源的一个高性能、灵活的机器人操作系统&#xff0c;cyber record 是 Cyber RT 中用于录制和回放数据的工具。下面是一个使用 Python 解析 cyber record 文件的示例&#xff0c;该示例使用 cyber_py 库&#xff08;Cyber RT 的 Python 绑定&#xff09;来读取记…