目录
1.在Http服务器接收到浏览器发送的【Http请求协议包】之后,自动为当前的【Http请求协议包】生成一个【请求对象】和一个【响应对象】
2.在Http服务器调用doGet/doPost方法时,负责将【请求对象】和【响应对象】作为实参传递到方法,确保doGet/doPost正确执行
3.在Http服务器准备推送Http响应协议包之前,负责将本次请求关联的【请求对象】和【响应对象】销毁
4.【请求对象】和【响应对象】生命周期贯穿一次请求的处理过程中
5.形象来说:【请求对象】和【响应对象】相当于用户在服务端的代言人
某些来自于浏览器发送请求,往往需要服务端中多个Servlet协同处理。
多个Servlet之间调用,根本目的是提高用户使用感受规则:无论本次请求涉及到多少个Servlet,用户只需要【手动】通知浏览器发起一次请求即可
多个Servlet之间调用规则:重定向解决方案、请求转发解决方案
原理
用户第一次通过【手动方式】通知浏览器访问OneServlet,OneServlet工作完毕后,将TwoServlet地址写入到响应头location属性中,
将302状态码写入到状态行。浏览器检查到302状态后,寻找响应头中的 location,然后立即自动向服务器发起第二次请求
即:浏览器至少发送两次请求,但是只有第一次请求是用户手动发送,后续请求都是浏览器自动发送的
重定向解决方案中,是通过地址栏通知浏览器发起下一次请求,因此通过重定向解决方案调用的资源文件接收的请求方式一定是【GET】
缺点:重定向解决方案需要在浏览器与服务器之间进行多次往返,大量时间消耗在往返次数上,增加用户等待服务时间
语法
response.sendRedirect("请求地址"); //将地址写入到响应包中响应头中location属性
请求地址可以是:外部网站的URL / 服务器内部的Servlet实现类对象的别名(即动态资源)/ 内部的静态资源
如果是内部资源,则URL的构成为: /网站名/Servlet对象对应的别名
示例

- <html>
- <head>
- <title>$Title$title>
- head>
- <body>
- <form action="/web4/s1" method="post">
- <input type="submit" value="重定向">
- form>
- body>
- html>

(Servlet1和Servlet2代码完全一致,只是数字有区别。在此只展示Servlet1的代码)
- public class Servlet1 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //...
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- resp.setContentType("text/html;charset=utf-8"); //设置content-Type中的字符规则为UTF-8,以保证显示到网页为中文
- PrintWriter out = resp.getWriter(); //获取输出流
-
- //提示S1的 POST被调用
- System.out.println("Servlet1 POST 被调用");
-
- //重定向到S2
- System.out.println("重定向到 /web4/s2");
- resp.sendRedirect("/web4/s2");
- }
- }

- public class Servlet2 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- resp.setContentType("text/html;charset=utf-8"); //设置content-Type中的字符规则为UTF-8,以保证显示到网页为中文
- PrintWriter out = resp.getWriter(); //获取输出流
-
- //提示S2的 GET被调用
- System.out.println("Servlet2 GET被调用");
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //...
- }
- }

- "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>
- <servlet-name>servlet1servlet-name>
- <servlet-class>Servlet1servlet-class>
- servlet>
- <servlet-mapping>
- <servlet-name>servlet1servlet-name>
- <url-pattern>/s1url-pattern>
- servlet-mapping>
-
-
- <servlet>
- <servlet-name>servlet2servlet-name>
- <servlet-class>Servlet2servlet-class>
- servlet>
- <servlet-mapping>
- <servlet-name>servlet2servlet-name>
- <url-pattern>/s2url-pattern>
- servlet-mapping>
-
- web-app>

结论:通过重定向自动发起的请求,都是GET类型的~
原理
用户第一次通过手动方式要求浏览器访问OneServlet。OneServlet工作完毕后,通过当前的请求对象 代替浏览器 向Tomcat发送请求,申请调用TwoServlet。
Tomcat在接收到这个请求之后,自动进入TwoServlet来完成剩余任务
在请求转发解决方案中,浏览器只发送一个了个Http请求协议包。参与本次请求的所有Servlet共享同一个请求协议包,因此这些Servlet接收的请求方式与浏览器发送的请求方式保持一致
请求次数:在请求转发过程中,浏览器只发送一次请求(无论本次请求涉及到多少个Servlet,用户只需要手动通过浏览器发送一次请求)
优点:Servlet之间调用发生在服务端计算机上,节省服务端与浏览器之间往返次数增加处理服务速度
语法
- RequestDispatcher report = request.getRequestDispatcher("/资源文件名"); //通过当前请求对象生成资源文件申请报告对象
- report.forward(当前请求对象,当前响应对象); //将报告对象发送给Tomcat
请求转发由于是内部Tomcat调度,而tomcat只对当前网站内部的资源有调度权力,所以资源文件名只能是服务器内部的静态 / 动态资源
资源文件名的书写注意细节:
由于是Tomcat内部调用,都是在同一个部署的网站中,所以资源文件名【不需要写网站的部署别名】!【直接写上需要访问的静态/资源名】即可。名字前面不要漏了斜杠: /
如果写了网站名,就会导致URL出现两个网站名,404错误

示例
web.xml 的配置文件和本小节中 “重定向Servlet调用” 一致,在此不再展示

- <html>
- <head>
- <title>$Title$title>
- head>
- <body>
- <form action="/web4/s1" method="post">
- <input type="submit" value="重定向">
- form>
-
- <form action="/web4/s2" method="get">
- <input type="submit" value="请求转发">
- form>
- body>
- html>

- public class Servlet1 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- resp.setContentType("text/html;charset=utf-8"); //设置content-Type中的字符规则为UTF-8,以保证显示到网页为中文
- PrintWriter out = resp.getWriter(); //获取输出流
-
- //提示S1的 GET被调用
- System.out.println("Servlet1 GET 被调用");
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //...
- }
- }

- public class Servlet2 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- resp.setContentType("text/html;charset=utf-8"); //设置content-Type中的字符规则为UTF-8,以保证显示到网页为中文
- PrintWriter out = resp.getWriter(); //获取输出流
-
- //提示S2的 GET被调用
- System.out.println("Servlet2 GET被调用");
-
- //请求转发到S1
- System.out.println("请求转发到 /web4/s1");
- //重定向中的URL无需写部署在Tomcat的网站名(因为本来就是内部调用了),只需要写资源名即可
- RequestDispatcher report = req.getRequestDispatcher("/s1"); //通过当前请求对象生成资源文件申请报告对象
- //RequestDispatcher report = req.getRequestDispatcher("/web4/s1"); //错误写法!不需要写网站部署名web4
- report.forward(req,resp); //将报告对象发送给Tomcat
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //...
- }
- }

结论:
通过请求转发的方式调用的其它Servlet的请求方式都是GET(因为共享一个请求、响应对象)
请求转发的URL只需要写 /资源名 即可(因为本身就是在同一个网站内,Tomcat默认在URL写上了网站部署别名)
什么是数据共享:OneServlet工作完毕后,将产生数据交给TwoServlet来使用
四种数据共享方案:
ServletContext接口【全局作用域对象】
Cookie类
HttpSession接口【会话作用域对象】
HttpServletRequest接口【请求作用域对象】
基本介绍
ServletContext是来自Servlet规范的一个接口,其实现类由Http服务器提供
ServletContext实现类的对象被称为【全局作用域对象】
若多个Servlet隶属于同一个网站下,则可以使用该方法进行Servlet数据共享
原理说明
每一个网站都存在一个全局作用域对象,该网站下的所有Servlet共享该对象
如:OneServlet可以将一个数据存入到全局作用域对象,当前网站中其他Servlet此时都可以从全局作用域对象得到这个数据进行使用
全局作用域对象生命周期
Tomcat启动过程中,自动为当前网站在内存中创建一个全局作用域对象
Tomcat运行期间,一个网站只有一个全局作用域对象
Tomcat运行期间,全局作用域对象一直处于存活状态(全局作用域对象生命周期贯穿网站整个运行期间)
Tomcat准备关闭时,负责将当前网站中全局作用域对象进行销毁处理
语法
K是String,V是Object
- //通过【请求对象】向Tomcat索要当前网站中【全局作用域对象】
- ServletContext application = request.getServletContext();
-
- //将数据添加到全局作用域对象作为【共享数据】
- application.setAttribute("key1",数据);
-
- //从全局作用域对象获取之前添加的共享数据【注意一下数据类型默认是Object,需要转换】
- Object 数据 = application.getAttribute("key1");
示例

- <html>
- <head>
- <title>$Title$title>
- head>
- <body>
- <form action="/web5/S1" method="get">
- <input type="text" name="v1">
- <input type="submit" value="发送数据v1到S1">
- form>
- body>
- html>

- "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>
- <servlet-name>S1servlet-name>
- <servlet-class>S1servlet-class>
- servlet>
- <servlet-mapping>
- <servlet-name>S1servlet-name>
- <url-pattern>/S1url-pattern>
- servlet-mapping>
-
- <servlet>
- <servlet-name>S2servlet-name>
- <servlet-class>S2servlet-class>
- servlet>
- <servlet-mapping>
- <servlet-name>S2servlet-name>
- <url-pattern>/S2url-pattern>
- servlet-mapping>
-
- web-app>

- public class S1 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- String v1 = (String)req.getParameter("v1");
- System.out.println("收到了来自index的参数 v1 = " + v1);
-
-
- /*【把数据存入ServletContext】*/
- ServletContext application = req.getServletContext(); //通过【请求对象】向Tomcat索要当前网站中【全局作用域对象】
- application.setAttribute("key1",v1); //将数据添加到全局作用域对象作为【共享数据】
- System.out.println("S1的数据成功存入全局作用域对象");
-
- /*【请求转发跳转到S2】*/
- System.out.println("正在从S1跳转到S2");
- System.out.println("=========================================================");
- RequestDispatcher report = req.getRequestDispatcher("/S2");
- report.forward(req,resp);
- }
- }

- public class S2 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- System.out.println("跳转到了S2");
-
- //从全局作用域对象拿到S1存入的值
- ServletContext application = req.getServletContext();
- String v2Fromv1 = (String)application.getAttribute("key1");
- System.out.println("S2拿到了从S1存入的数据: v2Fromv1 = " + v2Fromv1);
- }
- }
基本介绍
来自于Servlet规范中一个工具类,存在于Tomcat提供servlet-api.jar中
若两个Servlet来自于同一个网站,并且为同一个浏览器/用户提供服务,此时推荐借助于Cookie对象进行数据共享
原理说明
用户通过浏览器第一次向MyWeb网站发送请求申请OneServlet,OneServlet在运行期间创建一个Cookie存储与当前用户相关数据
OneServlet工作完毕后,【Cookie写入到响应头】交还给当前浏览器,浏览器收到响应响应包之后,将cookie存储在浏览器的缓存
一段时间之后,用户通过【同一个浏览器】再次向【myWeb网站】发送请求申请TwoServlet时,
浏览器会【无条件地将myWeb网站之前推送过来的Cookie写入到请求头】发送过去
此时TwoServlet在运行时,就可以通过读取请求头中cookie中信息,得到OneServlet提供的共享数据
生命周期
在默认情况下,Cookie对象存放在浏览器的缓存中。因此只要浏览器关闭,Cookie对象就被销毁掉
在手动设置情况下,可以要求浏览器将接收的Cookie存放在客户端计算机上硬盘上,同时需要指定Cookie在硬盘上存活时间。
在存活时间范围内,关闭浏览器关闭客户端计算机,关闭服务器,都不会导致Cookie被销毁。
在存活时间到达时,Cookie自动从硬盘上被删除
cookie.setMaxAge(60); //cookie在客户端硬盘存活时间(单位:秒) 在此期间用户即使关闭浏览器,也不会导致Cookie销毁
语法
存数据:创建一个cookie对象,通过Cookie的构造方法保存共享数据(当前用户数据)
cookie相当于一个map。一个cookie中只能存放一个键值对
K和V都只能是String,且Key不能是中文,但是V可以是中文
- Cookie card = new Cookie("key1","V");
- resp.addCookie(card); //将cookie写入到响应头,交给浏览器
在其它Servlet中取Cookie的数据:调用请求对象从请求头得到浏览器返回的Cookie
- //1.调用请求对象从请求头得到浏览器返回的Cookie
- Cookie cookieArray[] = request.getCookies();
-
- //2.循环遍历数据得到每一个cookie的key 与 value
- for(Cookie card:cookieArray){
- String key = card.getName(); //读取key "key1"
- String value = card.getValue(); //读取value "abc"
- }
示例
index 和 web.xml 的配置和上面一样,这里不再展示。

- public class S1 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
- Cookie card = new Cookie("key1","S1的值1");
- Cookie card2 = new Cookie("key2","S1的值2");
- Cookie card3 = new Cookie("key3","S1的值3");
- resp.addCookie(card); //将cookie写入到响应头,交给浏览器
- resp.addCookie(card2);
- resp.addCookie(card3);
-
- resp.sendRedirect("/web5/S2"); //将地址写入到响应包中响应头中location属性
- }
- }

- public class S2 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- System.out.println("跳转到了S2");
-
- //1.调用请求对象从请求头得到浏览器返回的Cookie
- Cookie cookieArray[] = req.getCookies();
-
- //2.循环遍历数据得到每一个cookie的key 与 value
- int i = 1;
- for(Cookie card:cookieArray){
- String key = card.getName(); //读取key "key1"
- String value = card.getValue(); //读取value "abc"
- System.out.println("数据" + i++ + ":" + key + " = " + value);
- }
- }
- }

基本介绍
来自于Servlet规范下一个接口。存在于Tomcat中servlet-api.jar,其实现类由Http服务器提供
开发人员习惯于将HttpSession接口修饰对象称为【会话作用域对象】
如果两个Servlet来自于同一个网站,并且为同一个浏览器 / 用户提供服务,此时推荐借助于HttpSession对象进行数据共享
原理说明
HttpSession 和 Cookie 的区别
【存储位置不同】Cookie:存放在客户端计算机(浏览器内存/硬盘);HttpSession:存放在服务端计算机内存
【可存储数据类型不同】Cookie:K只能是英文String,V只能是String;HttpSession:K的String可以含中文,V可以存储任意类型的共享数据Object
【数据数量】一个Cookie对象只能存储一个共享数据;HttpSession使用map集合存储共享数据,所以可以存储任意数量共享数据
HttpSession 是存放在服务端计算机内存中的,它是如何知道不同的HttpSession对象对应的是哪个用户呢?
HttpSession通过Cookie,将用户与HttpSession关联起来
生命周期
用户与HttpSession关联时使用的Cookie只能存放在浏览器缓存中
在浏览器关闭时,意味着用户与他的HttpSession关系被切断
由于Tomcat无法检测浏览器何时关闭,因此在浏览器关闭时并不会导致Tomcat将浏览器关联的HttpSession进行销毁
为了解决这个问题,Tomcat为每一个HttpSession对象设置【空闲时间】,这个空闲时间默认30分钟
如果当前HttpSession对象空闲时间达到30分钟,此时Tomcat认为用户已经放弃了自己的HttpSession,此时Tomcat就会销毁掉这个HttpSession
手动修改HttpSession空闲时间:
在web.xml中设置 (单位:分钟)
语法
添加数据
- //1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
- HttpSession session = request.getSession(); //如果当前用户还没有session对象,则服务端创建一个新的
- HttpSession session = request.getSession(false); //如果当前用户还没有session对象,则服务端不会创建新的,会返回一个null
-
- //2.将数据添加到用户私人储物柜
- session.setAttribute("key1",共享数据)
获取数据
- //1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
- HttpSession session = request.getSession();
- HttpSession session = request.getSession(false); //如果当前用户还没有session对象,则服务端不会创建新的,会返回一个null
-
- //2.从会话作用域对象得到OneServlet提供的共享数据
- Object 共享数据 = session.getAttribute("key1");
示例

- public class S1 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
- //1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
- HttpSession session = req.getSession(); //如果当前用户还没有session对象,则服务端创建一个新的
-
- //2.将数据添加到用户私人储物柜
- session.setAttribute("键1","值V1");
-
- //转到Servlet1中
- resp.sendRedirect("/web5/S2"); //将地址写入到响应包中响应头中location属性
- }
- }

- public class S2 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
- //1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
- HttpSession session = req.getSession();
-
- //2.从会话作用域对象得到OneServlet提供的共享数据
- Object o1 = session.getAttribute("键1");
- System.out.println(o1);
- }
- }

基本介绍
在同一个网站中,如果两个Servlet之间通过【请求转发】方式进行调用,彼此之间共享同一个请求协议包。
而一个请求协议包只对应一个请求对象,因此servlet之间共享同一个请求对象,
此时可以利用这个请求对象在两个Servlet之间实现数据共享
在请求对象实现Servlet之间数据共享功能时,开发人员将请求对象称为【请求作用域对象】
语法
- //将数据添加到【请求作用域对象】中attribute属性
- req.setAttribute("key1",数据); //数据类型可以任意类型Object
-
- //从当前请求对象得到OneServlet写入到共享数据【当前Servlet必须和之前的Servlet共用一个请求对象。即请求转发】
- Object 数据 = req.getAttribute("key1");
示例

- public class S1 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
- req.setAttribute("键1","值V"); //数据类型可以任意类型Object
-
- //请求转发
- RequestDispatcher report = req.getRequestDispatcher("/S2"); //通过当前请求对象生成资源文件申请报告对象
- report.forward(req,resp); //将报告对象发送给Tomcat
-
- }
- }

- public class S2 extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- System.out.println("跳转到了S2");
-
- Object o1 = req.getAttribute("键1");
- System.out.println(o1);
-
- }
- }
