
Tomcat简介
Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器,按照Sun
Microsystems提供的技术规范,实现了对Servlet和JavaServer
Page(JSP)的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台、安全局管理和Tomcat阀等。
Jakarta EE平台是Java EE平台的演进。Tomcat
10及以后的版本实现了作为Jakarta EE一部分开发的规范。Tomcat
9和更早版本的实现规范是作为Java EE的一部分开发的。
Apache
Tomcat本身完全开源免费,这也是它受到热烈欢迎的原因之一。Tomcat的作用是自己开发的APP,它的运行需要jre。jre是针对Java
SE的,如果需要运行Java
EE的程序就提供更多的支持,Tomcat的作用就是这个。
Web项目的标准结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Web Root | ├─── WEB-INF │ ├─── web.xml │ ├─── classes │ └─── lib │ ├─── Static Resources │ ├─── HTML Files │ ├─── CSS Files │ └─── JavaScript Files │ ├─── Dynamic Resources │ ├─── JSP Files │ └─── Servlet Files │ └─── Configuration Files ├─── web.xml ├─── context.xml └─── log4j.properties
|
其中WEB-INF目录下的资源是被保护的资源,不可以被浏览器访问。用来放第三方jar包,classes,web.xml等。
JSP 文件:JavaServer Pages(JSP)文件是用于创建动态
Web 内容的文件。它们通常位于 Web 根目录下的某个位置。JSP 文件包含 HTML
代码和 Java 代码,用于生成动态内容。当 JSP
文件被访问时,它们会被服务器编译成 Servlet
类,并由服务器进行处理和执行。
Servlet 文件:Servlet 是 Java Web
应用程序的核心组件之一,用于处理客户端请求并生成动态内容。Servlet
文件通常位于 WEB-INF 目录下的某个位置,可以通过映射 URL 来访问。Servlet
文件是 Java 类,实现了 Servlet 接口或扩展了 HttpServlet
类,通过重写相应的方法来处理请求和生成响应。
Servlet
简介
Servlet 是 Java EE(现在称为 Jakarta EE)平台中用于处理 Web
请求并生成响应的一种 Java
编程技术。不是所有的Java类都能处理客户端的请求,能处理客户端请求并做出响应的一套技术标准就是
Servlet。Servlet 是运行在服务器端的,所以必须在 Web 项目中开发并且在
Tomcat 这样的服务容器中运行。
- 静态资源:在程序运行之前就写好了的资源,比如hexo静态博客中的js,css,html文件
- 动态资源:程序运行时通过代码运行生成的资源,指的不是js创建的动画效果
Servlet用于接收、处理客户端请求、响应给浏览器的动态资源。是运行在Tomcat的Java小程序,是sum公司提供的一套自定义动态资源规范,从代码层面上讲
Servlet 就是一个接口。
工作流程
- Tomcat
接收到请求以后,会把请求的信息转换成一个
HttpServletRequest
对象,包含了请求消息中的所有信息。
- Tomcat
同时创建了一个
HttpServletResponse
对象,用来装要响应给客户端的信息,未来这个对象会被转换成响应消息。
- Tomcat 根据提供的路径找到对应的
Servlet,实例化,调用
service
方法,同时传入两个对象:HttpServletRequest
和HttpServletResponse
。从而获取请求消息;然后根据请求消息生成要响应给客户端的数据,将相应的数据放入HttpServletResponse
对象。
- 最后
HttpServletResponse
被转换成响应消息发回客户端。
我们需要自己定义一个 Servlet
类,实现接口Servlet
,重写service
方法。

举个例子,客户端提交一个用户名,如果用户名已经存在,那么返回No
。
- 创建一个Java项目,同时把 Tomacat 添加为依赖
- 重写
protected void service(HttpServletRequest req, HttpServletResponse resp)
- 在
service
方法中定义业务处理代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
<servlet> <servlet-name>userServlet</servlet-name> <servlet-class>servlet.UserServlet</servlet-class> </servlet>
<servlet-mapping> <servlet-name>userServlet</servlet-name> <url-pattern>/absolute</url-pattern> </servlet-mapping>
|
一个servlet-name
可以对应多个url-pattern
,但是一个url-pattern
只能和一个servlet-name
对应。
使用注解的方式可以完全替代上面复杂的web.xml
代码,只需要在自定义的public class UserServlet extends HttpServlet
类前加上注解@WebServlet("/自定义")
(也可以定义多个url)。这两种方式二选其一,不能重复。
插曲
servlet-api.jar
编码的时候需要,但是服务器内置,所以不参与打包,作用范围是provided
。
响应头中的 Content-Type 显示的是MIME类型,MIME
类型用于告诉客户端响应的数据是什么类型的数据。什么是MIME类型?
MIME 类型(Multipurpose Internet Mail Extensions) 是一种在 HTTP
通信或邮件传输中标识文件内容类型的标准方式。它告诉浏览器或其他客户端:服务器发送的内容属于哪种格式,应该如何处理。
MIME
格式:主类型/子类型
,例如text/html
指的是HTML文件。
conf/web.xml
中记录了几乎所有文件类型对应的MIME类型,例如:
1 2 3 4 5 6 7 8
| <mime-mapping> <extension>htm</extension> <mime-type>text/html</mime-type> </mime-mapping> <mime-mapping> <extension>html</extension> <mime-type>text/html</mime-type> </mime-mapping>
|
extension
指的是文件拓展名。Tomcat 通过这里记录的关系对
Content-Type
赋值。将相应的数据放入响应体中时可以调用对应的方法手动指定。
Servlet 生命周期
普通 Servlet
- 实例化——构造器,第一次请求//服务启动(这个执行阶段可自己指定,关键词
loadOnStartUp
)
- 初始化——init,构造完毕执行一次
- 接收请求,处理请求 服务——service,每次请求都执行
- 销毁——destroy,关闭服务时请求
Servlet
在 Tomcat
中是单例的。其中的成员变量在多个线程中是共享的,所以不建议在service方法中修改成员变量,否则会引发线程安全问题。
DefaultServlet
它被定义在 Tomcat 安装目录下的\conf\web.xml
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <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>
|
“目录列表浏览功能”:当你在浏览器中访问一个
目录路径,如果这个目录下没有默认的首页文件(如index.html
或index.jsp
),Tomcat
会尝试列出这个目录中的所有文件,这个功能就是所谓的目录列表浏览(Directory
Listing)。
在禁止目录列表浏览功能的情况下,就算找不到默认首页文件,也不会展示目录列表,直接返回403。这样可以防止用户发现敏感文件,不暴露Web应用的内部结构。
它主要处理:
- 静态文件(如
.html
、.css
、.js
、图片等)请求(最重要)
- 找不到匹配的
servlet
或映射时,作为“兜底”处理请求
SpringMVC 会导致 DefaultServlet
失效,无法访问静态资源,这时需要重新配置 DefaultServlet。
Servlet 接口
位于包javax.servlet
1 2 3 4 5 6 7
| public interface Servlet { void init(ServletConfig config) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; String getServletInfo(); void destroy(); }
|
void init
: 初始化 Servlet,只在 Servlet
第一次被加载时调用一次。
ServletConfig getServletConfig
: 返回 Servlet
的配置对象(ServletConfig),包含初始化参数等信息。
void service
: 处理客户端请求,是 Servlet
的核心方法。
String getServletInfo
: 返回一个字符串,用于描述 Servlet
的信息。一般用处不大,可以写作者名、版本号等。
void destroy
: 在 Servlet
被销毁之前调用,用于释放资源。可以用于关闭数据库连接、清理线程池等。
Servlet 实现类
这个接口有两个实现类:GenericServlet
和HttpServlet
GenericServlet
所在包:javax.servlet
。GenericServlet
是一个抽象类,实现了 Servlet
接口的大部分方法,但是没有实现service()
,所以还是抽象类。它与协议无关。
使用它的时候只需要重写service(ServletRequest req, ServletResponse res)
:
1 2 3 4 5 6 7
| public class MyServlet extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { res.getWriter().write("Hello from GenericServlet"); } }
|
HttpServlet
所在包:javax.servlet.http
,是GenericServlet
的子抽象类,专为处理
HTTP 请求设计。它为 HTTP 请求方法(GET、POST、PUT
等)提供了对应的回调方法。
1
| public abstract class HttpServlet extends GenericServlet{...}
|
关键源码:这是我们创建自定义类时要重写的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest)req; response = (HttpServletResponse)res; } catch (ClassCastException var6) { throw new ServletException(lStrings.getString("http.non_http")); } this.service(request, response); }
|
这里的形参列表中的ServletRequest
和ServletResponse
是实际使用的HttpServletRequest
和HttpServletResponse
的父类,我们使用的时候自动向下转型。
这个方法执行到最后会调用另一个被protected
的重载方法:
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
| protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals("GET")) { long lastModified = this.getLastModified(req); if (lastModified == -1L) { this.doGet(req, resp); } else { long ifModifiedSince; try { ifModifiedSince = req.getDateHeader("If-Modified-Since"); } catch (IllegalArgumentException var9) { ifModifiedSince = -1L; } if (ifModifiedSince < lastModified / 1000L * 1000L) { this.maybeSetLastModified(resp, lastModified); this.doGet(req, resp); } else { resp.setStatus(304); } } } else if (method.equals("HEAD")) { long lastModified = this.getLastModified(req); this.maybeSetLastModified(resp, lastModified); this.doHead(req, resp); } else if (method.equals("POST")) { this.doPost(req, resp); } else if (method.equals("PUT")) { this.doPut(req, resp); } else if (method.equals("DELETE")) { this.doDelete(req, resp); } else if (method.equals("OPTIONS")) { this.doOptions(req, resp); } else if (method.equals("TRACE")) { this.doTrace(req, resp); } else { String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(501, errMsg); }
}
|
上面这个方法负责根据客户端请求的 HTTP 方法,自动将请求分发到对应的
doGet, doPost 等方法。下面来看doGet
方法是如何实现的:
1 2 3 4
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String msg = lStrings.getString("http.method_get_not_supported"); this.sendMethodNotAllowed(req, resp, msg); }
|
作用是:如果没有重写doGet
,当用户发起 GET
请求时,就会用英文提示“GET 不被支持”返回 405 错误。
其他几个请求方法也都是一样的逻辑。只要用户没有重写这些方法,都会返回错误信息。这样保证了需要什么就用什么,用不到的请求方法也不会被意外调用。
不过,话虽如此,在实际使用中直接重写service
也是完全可以使用的,这样也比较方便。
后续使用 Spring 框架后,就不用再写这些了...
ServletConfig
ServletConfig 是什么?
ServletConfig
是为Servlet提供初始配置参数的一种对象,每个Servlet都有自己独立唯一的ServletConfig对象。
容器会为每个Servlet实例化一个ServletConfig对象,并通过Servlet的生命周期的init方法传入给Servelt作为属性。
一般配置方式:
在web.xml
中配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <servlet> <servlet-name>servlet1</servlet-name> <servlet-class>servlet.Servlet1</servlet-class>
<init-param> <param-name>keya</param-name> <param-value>valueA</param-value> </init-param> <init-param> <param-name>keyb</param-name> <param-value>valueB</param-value> </init-param>
</servlet> <servlet-mapping> <servlet-name>servlet1</servlet-name> <url-pattern>/s1</url-pattern> </servlet-mapping>
|
然后就可以在 Servlet
中读取<init-param>
中的参数了,这里提供了两种方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class Servlet1 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletConfig servletConfig = getServletConfig(); String a_parameter = servletConfig.getInitParameter("keya"); System.out.println("A: " + a_parameter); String b_parameter = servletConfig.getInitParameter("keyb"); System.out.println("B: " + b_parameter); System.out.println();
Enumeration<String> initParameterNames = servletConfig.getInitParameterNames(); while (initParameterNames.hasMoreElements()) { String name = initParameterNames.nextElement(); System.out.println(name + " : " + servletConfig.getInitParameter(name)); } } }
|
注解方式配置
使用@WebServlet
注解可以更简单地完成上述配置
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
| @WebServlet( urlPatterns = "/s1", initParams = {@WebInitParam(name="keya", value="valuea")} ) public class Servlet1 extends HttpServlet {
@Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletConfig servletConfig = getServletConfig(); String a_parameter = servletConfig.getInitParameter("keya"); System.out.println("A: " + a_parameter); String b_parameter = servletConfig.getInitParameter("keyb"); System.out.println("B: " + b_parameter); System.out.println();
Enumeration<String> initParameterNames = servletConfig.getInitParameterNames(); while (initParameterNames.hasMoreElements()) { String name = initParameterNames.nextElement(); System.out.println(name + " : " + servletConfig.getInitParameter(name)); } } }
|
打印结果:
1 2 3 4
| A: valuea B: null
keya : valuea
|
因为这时没有定义keyb
参数,所以第一种方法打印出来B为null,使用迭代的方法没有打印B
ServletContext
与ServletConfig
类似,它也可以提供初始化配置参数,但ServletContext
是为所有的Servlet对象提供公共的参数。

ServletContext
是一个全局的储存信息的空间,它被所有客户端共享,因此Servlet对象之间可以通过
ServletContext 对象来实现通讯。
修改 ServeletContext
1 2 3 4 5 6 7 8
| <context-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </context-param> <context-param> <param-name>password</param-name> <param-value>123456</param-value> </context-param>
|
获取 ServletContext 对象:
1 2 3
| public ServletContext getServletContext() { return this.getServletConfig().getServletContext(); }
|
调用servlet对象.getServletContext()
来获取 ServletContext
对象。
打印所有ServeletContext
的全局参数,也可以使用迭代的方法,同ServletConfig
:
1 2 3 4 5 6 7
| ServletContext servletContext = getServletContext(); Enumeration<String> initParameterNames = servletContext.getInitParameterNames(); while (initParameterNames.hasMoreElements()) { String initParameterName = initParameterNames.nextElement(); String initParameterValue = servletContext.getInitParameter(initParameterName); System.out.println(initParameterName + ": " + initParameterValue); }
|
但是注意:这里调用getInitParameter()
获取的是来自
web.xml
或注解配置的初始化参数,不可变,程序启动后不可改。如果想要获取程序运行时动态修改过的
ServletContext 属性,应当使用getAttribute
:
1 2 3 4 5 6 7 8 9 10 11 12 13
| System.out.println("--------- ServletContext init params ---------"); Enumeration<String> initParams = servletContext.getInitParameterNames(); while (initParams.hasMoreElements()) { String name = initParams.nextElement(); System.out.println("init param: " + name + " = " + servletContext.getInitParameter(name)); }
System.out.println("--------- ServletContext attributes ---------"); Enumeration<String> attrNames = servletContext.getAttributeNames(); while (attrNames.hasMoreElements()) { String name = attrNames.nextElement(); System.out.println("attribute: " + name + " = " + servletContext.getAttribute(name)); }
|
获取资源真实路径 API
getServletContext().getRealPath("/目录名")
示例:
在src/Servlet3.java
中写如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| @WebServlet( urlPatterns = "/s3", initParams = {@WebInitParam(name = "s3", value = "sdeddd")} ) public class Servlet3 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext(); String path = servletContext.getRealPath("upload"); System.out.println(path); } }
|
控制台输出:
1
| D:\Develop\web-all\out\artifacts\demo03_servletConfig_servletContext_war_exploded\upload
|
作用:
获取项目部署路径,也叫上下文路径。与手动指定的方式不同的是,这个路径不是写死的,随项目部署位置的改变而自动变化。这样一来,不管该项目实在本地运行还是未来放到服务器中运行,都可以成功找到正确的路径。
本例中的项目结构为

web
即项目的访问路径,upload
在开发项目中的的确切位置为web/upload
;在部署项目中的位置变成了demo03_servletConfig_servletContext_war_exploded\upload
,也就是我们刚才获取的真实路径。
域对象相关 API
域对象:即具有作用域(Scope)的对象。它们用于在
Web
应用中保存和共享数据。说白了,域对象就是一个放数据的对象,可以通过域对象来存值和取值,不同的域对象的范围不一样,也就限制了哪些类可以访问这个对象,进行值的存储,以达到数据交换的目的。
刚才提到的ServletContext
在一个Web
App中是唯一的,代表了这个应用,也叫应用域,是 Web App
中最大的域。
常见的域对象
域对象名称 |
接口类型 |
常用获取方式 |
request |
HttpServletRequest |
Servlet 方法参数或 JSP 中隐含对象 |
session |
HttpSession |
request.getSession() |
application(即 ServletContext ) |
ServletContext |
getServletContext() 或
application (JSP) |
page(只在 JSP 中) |
PageContext |
JSP 中隐含对象 pageContext |
域对象常用 API 方法
方法 |
作用 |
setAttribute(String name, Object value) |
设置(添加或修改)一个属性(键值对) |
getAttribute(String name) |
获取指定属性的值 |
removeAttribute(String name) |
移除指定属性 |
getAttributeNames() |
返回所有属性名的枚举(Enumeration 类型) |
setAttribute
1
| void setAttribute(String var1, Object var2);
|
var1
:
相当于哈希表中的键,不过必须是字符串类型,不可重复
var2
: 相当于哈希表中的值
getAttribute(String name): Object
- 获取键对应的值,但是
Object
类型,类似于Java的下界通配符,写入安全但是读取受限
Tomcat 在启动 Web 应用时会把Tomcat
内部运行所需的组件、路径、缓存等对象自动放入 ServletContext 的 attribute
属性表中,所以如果运行以下代码:
1 2 3 4 5 6
| System.out.println("--------- ServletContext attributes ---------"); Enumeration<String> attrNames = servletContext.getAttributeNames(); while (attrNames.hasMoreElements()) { String name = attrNames.nextElement(); System.out.println("attribute: " + name + " = " + servletContext.getAttribute(name)); }
|
会得到包含用户自定义属性在内的非常长的一串输出,但是其中系统自带的属性并不是我们所关心的。因此,如果要查看自己定义的属性,最好使用getAttribute(String name)
。
HttpServletRequest
1
| public interface HttpServletRequest extends ServletRequest {...}
|
它出现在service
方法:
1
| protected void service(HttpServletRequest req, HttpServletResponse resp) {...}
|
HttpServletRequest
提供了一系列可用于处理 HTTP
请求的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @WebServlet("/s4") public class Servlet4 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println(req.getMethod()); System.out.println(req.getScheme()); System.out.println(req.getProtocol()); System.out.println(req.getRequestURI()); System.out.println(req.getRequestURL()); System.out.println(req.getLocalPort()); System.out.println(req.getServerName()); System.out.println(req.getRemoteHost()); } }
|
运行一下:
1 2 3 4 5 6 7 8
| GET http HTTP/1.1 /demo03/s4 http://localhost:8080/demo03/s4 8080 localhost 0:0:0:0:0:0:0:1
|
URI:
统一资源标识符。用于标识某个资源。只要能唯一地定位资源,就是
URI。
URL: 统一资源定位符。URI
的一种,不仅标识资源,还指定了获取资源的协议和地址。
即:URL 是 URI 的一个子集,URI 更宽泛,URL 更具体。
0:0:0:0:0:0:0:1
是 IPv6 表示形式的本地回环地址,等价于
IPv4 的 127.0.0.1。
获取头
1 2 3 4 5
| Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); System.out.println(headerName + ": " + req.getHeader(headerName)); }
|
获取请求参数
getParameterMap()
返回一个Map<String, String[]>
的变量,使用forEach
遍历所有参数,这种处理方式也适用于多选的情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @WebServlet("/s5") public class Servlet5 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); System.out.println(username + " " + password);
Map<String, String[]> parameterMap = req.getParameterMap(); parameterMap.forEach((key, value) -> { System.out.println(key + " " + Arrays.toString(value)); }); } }
|
以上API专门用于键值对形式的参数,无论这些参数是在url中还是请求体中。get请求参数以键值对的形式放在url中,一般约定不放在请求体中。post方式放在请求体中。
以下API用于读取文本/文件/JSON:
1 2
| BufferedReader reader = req.getReader(); ServletInputStream inputStream = req.getInputStream();
|
HttpServletResponse
提供了一系列用于处理响应消息的方法:
setStatus
: 设置状态码
setHeader
: 设置响应头的字段,传入字段名和字段值
setContentType
: 设置 MIME
类型,如前所述,作用是告诉客户端响应的数据是什么类型的数据。其实用setHeader
也能完成,但是因为太过重要所以单独封装了一个方法
setContentLength
:设置传输的内容长度,同样用setHeader
也能完成,但是因为太过重要所以单独封装了一个方法
getWriter
:
获取一个字符输出流PrintWriter
,用于设置响应体的内容
请求转发和响应重定向
请求转发(Forward)
响应重定向(Redirect)
forward 转发
服务器内部跳转,浏览器地址栏不变。
用法:
1 2 3 4 5 6 7 8 9 10 11
| @WebServlet("/s1") public class servlet1 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet1 service"); RequestDispatcher s2 = req.getRequestDispatcher("s2"); s2.forward(req, resp); } }
|
客户端只产生一次请求,服务端只产生一次req和resp,这一对req和resp可以一直传递下去。
当然,getRequestDispatcher
传入的参数不仅仅局限于 Servlet
,也可以是一个文件:
1 2
| req.getRequestDispatcher("test.html").forward(req, resp);
|
就算是 WEB-INF 中的资源也可以通过这种方式被访问,这也是 WEB-INF
访问的唯一方式。
也就是说,目标资源既可以是动态资源,也可以是静态资源,也可以是受保护的资源,但是不能是外部资源。
redirect 重定向
语法:
1
| resp.sendRedirect("test.html");
|
- 通过
HttpServeltResponse
对象的sendRedirect
方法实现
- 响应重定向是服务端通过302响应码和
location
资源路径,告诉客户端让它自己去找其他资源,属于在服务器的提示下的客户端的行为。
- 客户端至少发送了两次请求,客户端地址栏是要变化的。
- 服务端产生了多对请求和响应对象,且请求和响应对象不会传递给下一个资源
- 重定向可以是Servlet动态资源,也可以是其他静态资源
- 不可以访问WEB-INF下受保护的资源(显然)
- 可以重定向到本项目以外的资源。
参考链接