【Servlet】6:一篇文章搞懂Servlet对象的相互调用、数据共享

本文章属于后端全套笔记的第三部分

(更新中)【后端入门到入土!】Java+Servlet+JDBC+SSM+SpringBoot+SpringCloud 基础入门_m0_57265007的博客-CSDN博客一篇文章,后端入门到入土。包含 Java基础+高级、MySQL、JDBC、Servlet、SSM、SpringBoot、SpringCloud、项目 的笔记。https://blog.csdn.net/m0_57265007/article/details/127962617?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22127962617%22%2C%22source%22%3A%22m0_57265007%22%7D

| 请求对象和响应对象 生命周期

1.在Http服务器接收到浏览器发送的【Http请求协议包】之后,自动为当前的【Http请求协议包】生成一个【请求对象】和一个【响应对象】

2.在Http服务器调用doGet/doPost方法时,负责将【请求对象】和【响应对象】作为实参传递到方法,确保doGet/doPost正确执行

3.在Http服务器准备推送Http响应协议包之前,负责将本次请求关联的【请求对象】和【响应对象】销毁

4.【请求对象】和【响应对象】生命周期贯穿一次请求的处理过程中

5.形象来说:【请求对象】和【响应对象】相当于用户在服务端的代言人


| Servlet之间的相互调用

Servlet调用 基本概述

  • 某些来自于浏览器发送请求,往往需要服务端中多个Servlet协同处理。

  • 多个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 {
        //...
    }
}

 

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

    <!--Servlet1实现类 注册-->
    <servlet>
        <servlet-name>servlet1</servlet-name>
        <servlet-class>Servlet1</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>servlet1</servlet-name>
        <url-pattern>/s1</url-pattern>
    </servlet-mapping>

    <!--Servlet2实现类 注册-->
    <servlet>
        <servlet-name>servlet2</servlet-name>
        <servlet-class>Servlet2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>servlet2</servlet-name>
        <url-pattern>/s2</url-pattern>
    </servlet-mapping>
    
</web-app>

 

结论:通过重定向自动发起的请求,都是GET类型的~

 

请求转发Servlet调用

原理

  • 用户第一次通过手动方式要求浏览器访问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写上了网站部署别名)


| Servlet之间的数据共享

Servlet数据共享 基本概述

  • 什么是数据共享:OneServlet工作完毕后,将产生数据交给TwoServlet来使用

  • 四种数据共享方案:

    • ServletContext接口【全局作用域对象】

    • Cookie类

    • HttpSession接口【会话作用域对象】

    • HttpServletRequest接口【请求作用域对象】


ServletContext接口 数据共享

基本介绍

  • 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>

 

<?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">
    
    <servlet>
        <servlet-name>S1</servlet-name>
        <servlet-class>S1</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>S1</servlet-name>
        <url-pattern>/S1</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>S2</servlet-name>
        <servlet-class>S2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>S2</servlet-name>
        <url-pattern>/S2</url-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);
    }
}

 

Cookie类 数据共享

基本介绍

  • 来自于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);
        }
    }
}

 

 

HttpSession接口 数据共享

基本介绍

  • 来自于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中设置 <session-config><session-timeout>5</session-timeout></session-config> (单位:分钟)

语法

添加数据

//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);
    }
}

 

 

HttpServletRequest接口 数据共享

基本介绍

  • 在同一个网站中,如果两个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);

    }
}

 

猜你喜欢

转载自blog.csdn.net/m0_57265007/article/details/128005937