目录
| 请求对象和响应对象 生命周期
| Servlet之间的相互调用
Servlet调用 基本概述
重定向Servlet调用
请求转发Servlet调用
| Servlet之间的数据共享
Servlet数据共享 基本概述
ServletContext接口 数据共享
Cookie类 数据共享
HttpSession接口 数据共享
HttpServletRequest接口 数据共享
(更新中)【后端入门到入土!】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);
}
}