努力有时候也战胜不了天分,但至少能让别人看得起你。
——《七龙珠》
手动创建一个Maven项目
由于要学习Java中的Servlet,Filter,Listener等组件需要下载依赖,所以我们需要在构建工具中进行演示和学习。本文使用Maven项目作为示例。
创建文件夹结构
1 2
| mkdir -p myapp/src/main/java cd myapp
|
手动创建一个简单的 pom.xml
1 2 3 4 5 6 7 8 9 10 11 12
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId> <artifactId>myapp</artifactId> <version>1.0-SNAPSHOT</version> </project>
|
这样我们就创建好了一个最简单maven项目。
Servlet
Servlet 是JavaWeb技术的核心组件,本质上就是运行在服务器端的小程序,用于处理客户端(如浏览器)的请求,生成动态响应。Servlet主要用于处理Http请求,实现动态网页内容生成。
Servlet 生命周期
Servlet的生命周期由Servlet容器(如Tomcat)管理,主要有以下几个阶段:
Servlet容器:Web服务器,用于接收HTTP请求并调用你写的Servlet 代码处理请求。
初始化 init()
–只调用一次
- 在Servlet第一次被访问时,容器会创建一个Servlet实例,然后调用它的
init()
方法。
- 通常用来做资源的初始化操作、比如数据库连接、读取配置文件等。
1 2 3 4
| @Override public void init() throws ServletException { System.out.println("Servlet 初始化:init()"); }
|
注:只有一个实例,init()只调用一次
请求处理 service()
–每次请求都会调用
- 每次有客户端请求Servlet,Tomcat就会调用Servlet实例的
service()
方法
service()
实例会自动判断请求类型(GET/POST),然后分发给对应的doGet() 或 doPost()
1 2 3 4 5 6 7 8 9 10
| @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("处理 GET 请求"); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("处理 POST 请求"); }
|
注:此处我们先暂时了解大概流程,无需关心代码实际实现
销毁 destroy()
–只调用一次
- 当Tomcat关闭、或Servlet被卸载(如热更新时),容器会调用
destroy()
方法
- 通常用来释放资源,如关闭数据库连接,停止线程等。
1 2 3 4
| @Override public void destroy() { System.out.println("Servlet 被销毁:destroy()"); }
|
补充说明
- 一个Servlet类只被实例化一次(单例),多个请求公用一个实例,线程不安全。
- Servlet生命周期由容器自动管理,你无需手动调用这些方法
- SpringMVC的低层DispatchServlet也是一个Servlet,生命周期和你写的一样。
部署Tomcat
Apache 基金会开发的免费、开源、轻量级 Java Web 容器 ,支持 Servlet 和 JSP 规范
- SpringBoot + SpringMVC 中内置Tomcat,无需配置容器,直接Main方法运行。
首先我们在官网下载安装TomCat:Apache Tomcat® - Welcome!
安装后记住安装路径,后面要用。
然后我们在VScode中安装扩展:

这个扩展帮助我们管理和启动Tomcat。
安装完成后,我们在VScode的侧边栏中的SERVICE中找到这个扩展(注意在资源管理器栏的最下面):

我们右键这个服务选择:Creat New Server
现在我们查看VScode的最上面,询问我们是否需要下载server,由于我们之前已经手动下载过Tomcat,所以选择No。
然后我们在弹出的窗口中选择之前安装的Tomcat的文件夹,来到这个页面:

不用更改配置,直接滑倒最下面点击Finish即可。
现在我们看到扩展中已经托管了Tomcat:

现在我们创建项目结构如下:
1 2 3 4 5 6 7
| servlet-lifecycle-demo/ ├── pom.xml ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/example/LifecycleServlet.java
|
pom.xml文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId> <artifactId>servlet-lifecycle-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging>
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> </dependencies>
<build> <finalName>servlet-lifecycle-demo</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.1</version> </plugin> </plugins> </build> </project>
|
LifecycleServlet.java 文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package com.example;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException;
@WebServlet("/life") public class LifecycleServlet extends HttpServlet {
public LifecycleServlet() { System.out.println("🚀 构造方法:Servlet 实例被创建"); }
@Override public void init() throws ServletException { System.out.println("🔧 init():Servlet 被初始化"); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("📥 doGet():处理 GET 请求"); resp.setContentType("text/html;charset=UTF-8"); resp.getWriter().write("<h2>你好,这是 Servlet 生命周期演示</h2>"); }
@Override public void destroy() { System.out.println("🧹 destroy():Servlet 被销毁"); } }
|
然后我们在终端中输入:
好,现在我们只需要右键Tomcat选择:add Deployment

然后选择File:

选择我们刚刚编译好的wer文件:

最后选择No:

我们就将刚刚编写好的Servlet加入了Tomcat容器中。
右键Tomcat服务选择Start Server,服务开始运行。此时打印的信息只有Tomcat的启动信息,Servlet还没有被创建。

然后我们浏览器访问:http://localhost:8080/servlet-lifecycle-demo/life
看到servlet实例被创建,然后调用了一次GET请求,

之后再次访问页面,也不会在创建新的Servlet实例,而是一直调用同一个实例的doGet方法

最后我们Stop Server:

我们可以在日志中找到Servlet销毁函数调用是打印的日志。
Servlet Mapping
Servlet的作用是将客户端发送的请求URL路径与特定的Servlet 类关联起来。当接收到符合某个映射规则的请求时,它会将请求交给对应的Servlet来处理。
使用 @WebServlet
注解配置映射
在我们上面的代码中,我们使用
1 2
| @WebServlet("/life") public class LifecycleServlet extends HttpServlet
|
进行注解配置。这里的”/life” 就是一个URL模式(URL pattern), 当用户访问路径 /life
时,Tomcat就会将这个请求交给 LifecycleServlet
的实例来处理。
多个URL模式:可以为一个Servlet映射多个URL模式
1
| @WebServlet({"/life","/mylife"})
|
这样当访问多个路径中的任意一个路径时,都会交给 LifecycleServlet
实例进行处理
指定 name
:可以为Servlet指定一个名称
1 2 3 4
| @WebServlet(name = "lifecycleServlet", urlPatterns = {"/life"}) public class LifecycleServlet extends HttpServlet { }
|
在注解映射时,name属性通常不是必须的,但是在web.xml中,servlet-name属性是必须的,所以这里介绍一下。
使用 web.xml
配置映射(传统方式)
在web应用的 WEB-INF
目录下,会有一个web.xml文件。我们也可以通过这个文件进行Servlet配置和Servlet映射。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <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> <servlet-name>lifecycleServlet</servlet-name> <servlet-class>com.example.LifecycleServlet</servlet-class> </servlet>
<servlet-mapping> <servlet-name>lifecycleServlet</servlet-name> <url-pattern>/life</url-pattern> </servlet-mapping>
</web-app>
|
<servlet>
用于声明一个Servlet,通过 <servlet-name>
指定名称(必须),<servlet-class>
指定Servlet类的完整限定名。
<servlet-mapping>
元素用于将一个Servlet名称 <servlet-name>
映射到一个URL模式 <url-pattern>
URL模式的类型
- 精确匹配:以
/
开头,例如 /life
。只用当请求的路径与此路径完全匹配时,Servlet才会被调用。
- 路径匹配:以
/
开头,以 /*
结尾,例如 /admin/*
。任何以 /admin/
开头的请求都会被匹配到这个Servlet。
- 扩展名匹配:以
*.
开头,例如 *.do
。任何以 .do
结尾的请求都会被匹配到这个Servlet
- 默认Servlet:只有一个
/
作为URL模式,他会处理所有其他Servlet映射都无法匹配的请求。
Servlet特性
Servlet的线程安全性:
- Servlet实例是单例的,但是对于每个请求,Servlet容器都会创建一个新的线程来执行Servlet的
service()
方法(doGet()
或 doPost()
)
- Servlet需要考虑线程安全性。避免在Servlet的实例变量中存储共享的可变状态,或者采取同步措施来保护共享资源。
Servlet的配置(ServletConfig):
- ServletConfig 对象代表Servlet的配置信息,每个servlet都有自己的ServletConfig对象。
- 我们可以在
web.xml
(或使用 @WebInitParam
注解)为Servlet配置初始化参数,并通过 ServletConfig
的 getInitParameter(String name)
方法获取。
一个小DEMO
1 2 3 4 5 6 7 8
| <servlet> <servlet-name>helloConfig</servlet-name> <servlet-class>com.example.HelloConfig</servlet-class> <init-param> <param-name>exampleParam</param-name> <param-value>Hello from config!</param-value> </init-param> </servlet>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class HelloConfig extends HttpServlet {
private String exampleParam;
@Override public void init(ServletConfig config) throws ServletException { super.init(config); exampleParam = config.getInitParameter("exampleParam"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); resp.getWriter().write("<h2>" + exampleParam + "</h2>"); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @WebServlet(urlPatterns = "/hello") @WebInitParam(name = "exampleParam", value = "Hello from annotation!") public class HelloAnnotation extends HttpServlet { private String exampleParam;
@Override public void init(ServletConfig config) throws ServletException { super.init(config); exampleParam= config.getInitParameter("exampleParam"); System.out.println("Greeting from annotation: " + exampleParam); }
}
|
无论使用注解还是web.xml在Servlet类中获取初始化参数的方法都一样。只是注册参数的方法不同。
Servlet API详解
Servlet API 是构建Java Web 应用的核心。它定义了Servlet容器和你的Servlet之间的契约。
HttpServletRequest 接口
HttpServletRequest
对象代表了客户端发送给Servlet的HTTP请求。通过这个对象,你可以获取到请求的所有信息。
常用方法:
获取参数时,如果没有设置该参数,则会得到 null
getParameter(String name)
: 获取指定名称的请求参数的值(返回 String
)。如果参数不存在或有多个同名参数,行为可能不确定。
getParameterValues(String name)
: 获取指定名称的所有请求参数的值(返回 String[]
)。
getParameterMap()
: 获取所有请求参数的 Map<String, String[]>
。
getHeader(String name)
: 获取指定名称的请求头的值(返回 String
)。
getHeaders(String name)
: 获取指定名称的所有请求头的值(返回 Enumeration<String>
)。
getHeaderNames()
: 获取所有请求头的名称(返回 Enumeration<String>
)。
getMethod()
: 获取请求的 HTTP 方法(例如:”GET”, “POST”)。
getRequestURI()
: 获取请求的 URI。
getContextPath()
: 获取 Web 应用的上下文路径。
getServletPath()
: 获取 Servlet 的路径。
getQueryString()
: 获取查询字符串(URL 中 ?
后面的部分)。
getRemoteAddr()
: 获取发送请求的客户端的 IP 地址。
getRemoteHost()
: 获取发送请求的客户端的主机名。
getSession()
: 返回当前请求关联的 HttpSession
,如果不存在则创建一个新的。
getSession(boolean create)
: 返回当前请求关联的 HttpSession
,如果 create
为 true
且不存在则创建一个新的,否则返回 null
。
setAttribute()
:HttpServletRequest
的属性只在当前请求的处理过程中有效,当该请求的响应发送回客户端后,这些属性就不再需要了
getAttribute()
:获取设置的属性。
练习1:获取get请求中的参数 name=ulna&age=20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| package com.example;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException; import javax.servlet.ServletConfig;
import java.util.Enumeration; import java.util.Map;
@WebServlet(name = "Test1", urlPatterns = {"/test1"}) public class HttpServletRequestTest1 extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name"); String age = req.getParameter("age"); Map <String, String[]> parameterMap = req.getParameterMap(); String nameMap = parameterMap.get("name")[0]; String ageMap = null; if (parameterMap.containsKey("age")) { ageMap = parameterMap.get("age")[0]; }
Enumeration<String> headerNames = req.getHeaderNames();
String userAgent = req.getHeader("user-agent"); System.out.println("User-Agent: " + userAgent);
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().println("<html><body>"); resp.getWriter().println("<h1>Request Method: " + req.getMethod() + "</h1>"); resp.getWriter().println("<h1>Received Parameters</h1>"); resp.getWriter().println("<p>Name: " + name + "</p>"); resp.getWriter().println("<p>Age: " + age + "</p>"); resp.getWriter().println("<h2>Using Map Method</h2>"); resp.getWriter().println("<p>Name from Map: " + nameMap + "</p>"); resp.getWriter().println("<p>Age from Map: " + ageMap + "</p>"); resp.getWriter().println("<h2>Request Headers</h2>"); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); String headerValue = req.getHeader(headerName); resp.getWriter().println("<p>" + headerName + ": " + headerValue + "</p>"); } resp.getWriter().println("<h1>Context Path: " + req.getContextPath() + "</h1>"); resp.getWriter().println("<h1>Servlet Path: " + req.getServletPath() + "</h1>"); resp.getWriter().println("</body></html>"); }
}
|
HttpServletResponse 接口
HttpServletResponse
对象代表了Servlet发送给客户端的Http响应。通过这个对象,我们可以设置响应的内容、状态码、响应头等信息。
常用方法:
getWriter()
: 返回一个 PrintWriter
对象,你可以使用它向客户端发送文本数据。
getOutputStream()
: 返回一个 ServletOutputStream
对象,你可以使用它向客户端发送二进制数据(例如:图片、文件)。
setContentType(String type)
: 设置响应的内容类型(例如:”text/html”, “application/json”)。同时也可以设置字符编码,例如 "text/html;charset=UTF-8"
。
setStatus(int sc)
: 设置响应的状态码(例如:200, 404, 500)。
sendError(int sc, String msg)
: 发送一个错误响应到客户端,并设置状态码和错误消息。
sendRedirect(String location)
: 发送一个临时的重定向响应,告诉客户端浏览器去访问另一个 URL。
setHeader(String name, String value)
: 设置指定的响应头。
addHeader(String name, String value)
: 添加指定的响应头(允许有多个同名 header)。
setDateHeader(String name, long date)
: 设置日期格式的响应头。
setIntHeader(String name, int value)
: 设置整数格式的响应头。
setContentLength(int len)
: 设置响应内容的长度。
练习2:创建一个Servlet,当通过访问特定的URL时如:/redirect-me
, 他会使用sendRedirect() 方法将客户端重定向到另一个你指定的URL例如:https://www.google.com
1 2 3 4 5 6 7 8 9 10
| @WebServlet(name = "Redirect", urlPatterns = {"/redirect-me"}) public class HttpServletRequestTest1 extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.sendRedirect("https://www.google.com"); }
}
|
ServletConfig 接口
每个Servlet都有一个对应的 ServletConfig
对象,Servlet 容器在构建Servlet时会创建这个对象,并传递给Servlet的 init(ServletConfig config)
方法。ServletConfig
接口允许你访问Servlet的配置信息。
注册初始参数:
只有一个参数时:通常可以这样简化写
1 2 3
| @WebServlet(name = "ConfigTest", urlPatterns = {"/configTest"}) @WebInitParam(name = "param1", value = "value1") public class ConfigTest extends HttpServlet
|
多个参数时:规范写法
1 2 3 4 5 6 7
| @WebServlet(name = "ConfigTest", urlPatterns = {"/configTest"}, initParams = { @WebInitParam(name = "param1", value = "value1"), @WebInitParam(name = "param2", value = "value2"), }) public class ConfigTest extends HttpServlet
|
常用方法:
getServletName()
: 返回 Servlet 的名称,通常是在 web.xml
或使用 @WebServlet
注解时指定的。
getInitParameter(String name)
: 返回 Servlet 初始化参数中指定名称的值(返回 String
)。这些参数可以在 web.xml
中通过 <init-param>
标签配置,或者在使用注解时通过 @WebInitParam
配置。
getInitParameterNames()
: 返回包含所有 Servlet 初始化参数名称的 Enumeration<String>
.
getServletContext()
: 返回当前 Web 应用的 ServletContext
对象。
练习3:创建一个Servlet,通过 @WebInitPara
注解配置至少两个初始化参数。在Servlet的 doGet()
方法中获取并显示这些初始化参数的值以及servlet的名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @WebServlet(name = "ConfigTest", urlPatterns = {"/configTest"}, initParams = { @WebInitParam(name = "param1", value = "value1"), @WebInitParam(name = "param2", value = "value2"), }) public class ConfigTest extends HttpServlet { private String param1; private String param2;
@Override public void init(ServletConfig config) throws ServletException{ super.init(config); param1 = config.getInitParameter("param1"); param2 = config.getInitParameter("param2"); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/plain"); resp.getWriter().println("Servlet Name: " + getServletConfig().getServletName()); resp.getWriter().println("Param1: " + param1); resp.getWriter().println("Param2: " + param2); }
}
|
ServletContext 接口
ServletContext
接口代表了当前的Web应用程序。它是整个Web应用共享的上下文,所有的Servlet、Filter、Listener 等都可以访问同一个 ServletContext
对象。Servlet 容器在启动Web应用时创建 ServletContext
对象。
常用方法:
getAttribute(String name)
: 返回指定名称的应用程序级别的属性值(返回 Object
)。
setAttribute(String name, Object object)
: 设置应用程序级别的属性/对象。
removeAttribute(String name)
: 移除指定名称的应用程序级别的属性。
getInitParameter(String name)
: 返回 Web 应用的上下文初始化参数中指定名称的值(返回 String
)。这些参数在 web.xml
的 <context-param>
标签中配置。
getInitParameterNames()
: 返回包含所有 Web 应用上下文初始化参数名称的 Enumeration<String>
.
getResource(String path)
: 返回指定路径的资源 URL。路径以 /
开头,相对于 Web 应用的根目录。
getResourceAsStream(String path)
: 返回指定路径的资源输入流。
getContextPath()
: 返回 Web 应用的上下文路径。
getServletContextName()
: 返回 Web 应用的名称(如果在部署描述符中指定了)。
log(String msg)
: 将消息写入 Servlet 容器的日志。
练习4:
- 在你的web应用的web.xml文件种配置至少一个
<context-param>
- 创建一个Servlet,该Servlet 获取并显示这个上下文参数的值。
- 在该Servlet中,设置一个ServletContext属性,并在同一个Servlet中获取并显示这个属性的值。
web.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <context-param> <param-name>appName</param-name> <param-value>LearnServlet</param-value> </context-param> <context-param> <param-name>blogName</param-name> <param-value>https: </context-param> </web-app>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| @WebServlet(name = "ContextTest", urlPatterns = {"/contextTest"} ) public class ContextTest extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = getServletContext();
String appName = context.getInitParameter("appName"); String blogName = context.getInitParameter("blogName"); String contextPath = context.getContextPath(); String ServletContextName = context.getServletContextName(); Map<String,Integer> map = new HashMap<>(); map.put("appName", 1); map.put("blogName", 2); map.put("contextPath", 3); map.put("ServletContextName", 4); context.setAttribute("ServletContext", map);
resp.setContentType("text/html;charset=UTF-8"); resp.getWriter().println("<html><body>"); resp.getWriter().println("<h1>Context Parameters</h1>"); resp.getWriter().println("<p>Application Name: " + appName + "</p>"); resp.getWriter().println("<p>Blog Name: " + blogName + "</p>"); resp.getWriter().println("<p>Context Path: " + contextPath + "</p>"); resp.getWriter().println("<p>Servlet Context Name: " + ServletContextName + "</p>"); resp.getWriter().println("<h2>Context Attributes</h2>"); resp.getWriter().println("<ul>"); Map<String, Integer> contextMap = (Map<String, Integer>) context.getAttribute("ServletContext"); for (Map.Entry<String, Integer> entry : contextMap.entrySet()) { resp.getWriter().println("<li>" + entry.getKey() + ": " + entry.getValue() + "</li>"); } resp.getWriter().println("</ul>"); resp.getWriter().println("</body></html>"); }
}
|
Servlet 请求转发与重定向
请求转发
请求转发是指将当前请求的处理交给web服务器上的另一个资源来完成,这个过程发生在服务器内部,客户端浏览器只发送一次请求(与重定向的一个关键不同)。
实现方式:
通过 RequestDispatcher
接口来实现请求转发。我们可以通过 HttpServletRequest
对象的 getRequestDispatcher(String path)
方法获取一个 RequestDispatcher
对象。path 可以是相对于当前Servlet上下文路径。
RequestDispatcher
接口提供了两个主要方法用于转发:
forword(ServletRequest request, ServletResponse response)
:将请求转发给另一个资源。
- 注意:在转发后,
forword()
后的代码有可能会执行。但是在调用之后,当前Servlet不应该再向客户端发送任何响应。最佳实践是 forwrod()
后就立即结束当前方法。
include(ServletRequest request, ServletResponse response)
:将另一个资源的内容包含到当前响应中。执行流程会回到当前Servlet继续处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @WebServlet("/first") public class FirstServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setAttribute("message", "Hello from FirstServlet"); RequestDispatcher dispatcher = request.getRequestDispatcher("/second"); System.out.println("FirstServlet: Forwarding request to /second"); dispatcher.forward(request, response); System.out.println("FirstServlet: After forwarding"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @WebServlet("/second") public class SecondServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String message = (String) request.getAttribute("message"); response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE html>"); out.println("<html><head><title>Second Servlet</title></head><body>"); out.println("<h1>Second Servlet 处理请求</h1>"); if (message != null) { out.println("<p>Message from previous servlet: " + message + "</p>"); } else { out.println("<p>No message passed.</p>"); } out.println("</body></html>"); System.out.println("SecondServlet: Request processed."); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
请求重定向
请求重定向是指服务器告诉客户端浏览器发送一个新的HTTP请求到另一个URL。这涉及到两次HTTP请求-响应周期。
实现方式:
通过 HttpServletResponse
对象的 sendRedirect(String location)
方法来发送重定向响应。
location
是客户端浏览器需要重新访问的URL。
1 2 3 4 5 6 7 8 9 10 11 12
| @WebServlet("/redirect-google") public class RedirectServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("RedirectServlet: Received request, redirecting to Google."); response.sendRedirect("https://www.google.com"); System.out.println("RedirectServlet: After sending redirect."); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|