目录
8.多个Servlet之间的调用规则
8.1 概述
某些来自于浏览器发送的请求,往往需要服务端中多个Servlet协调处理,但是浏览器一次只能访问一个Servlet,导致用户需要手动通过浏览器发起多次请求才能得到服务,这样会增加用户获得服务的难度,导致用户放弃访问当前网站。
为了提高用户的使用感受,需要做到无论本次请求涉及多少哥Servlet,用户只需要手动通知浏览器一次请求即可。
多个Servlet之间的调用规则:
①重定向解决方案
②请求转发解决方案
8.2 重定向解决方案
工作原理:用户第一次通过手动方式通知浏览器访问OneServlet,OneServlet工作完毕后,将TwoServlet的地址写入到响应头location属性中,导致Tomcat服务器将状态码302写入到状态行。在浏览器接收到响应包之后,会读取到302状态,此时浏览器自动根据响应头中location属性中的地址发起第二次请求,访问TwoServlet去完成请求中的剩余任务。
实现命令:
response.sendRedirect("请求地址");
public class OneServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("OneServlet 负责洗韭菜");
//重定向结局方案
response.sendRedirect("/myWeb/two");//[地址格式:/网站名/资源文件名]
}
}
public class TwoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("TwoServlet 负责韭菜炒鸡蛋");
}
}
特征:
①既可以把当前网站内部的资源文件地址发送给浏览器,也可以把其他网站资源文件地址发
送给浏览器。
如果是当前网站的,地址填写:/网站名/资源文件名
如果是其他网站的,地址填写:http://IP地址:端口号/网站名/资源文件名
②浏览器至少发送两次请求,但是只有第一次请求是用户手动发送的,后续请求都是浏览器
自动发送的。
③重定向解决方案中,通过地址栏通知浏览器发起下一次请求,因此通过重定向解决方案调
用的资源文件接收的请求方式一定是Get。
缺点:重定向解决方案需要在浏览器与服务器之间进行多次往返,大量时间消耗在往返次数上,增加用户等待服务的时间。
8.3 请求转发解决方案
工作原理:用户第一次通过手动方式要求浏览器访问OneServlet,OneServlet工作完毕后,通过当前的请求对象代替浏览器向Tomcat发送请求,申请调用TwoServlet,Tomcat在接收到这个请求之后,自动调用TwoServlet来完成剩余任务。
实现命令:请求对象代替浏览器向Tomcat发送请求
//1.通过当前请求对象生成资源文件申请报告对象
RequestDispatcher report = request.getRequestDispatcher("/资源文件名");//一定以"/"开头
//2.将报告对象发送给Tomcat
report.forward(当前请求对象,当前响应对象);
public class OneServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("OneServlet ");
//请求转发方案:
//1.通过当前请求对象生成资源文件申请报告对象
RequestDispatcher report = request.getRequestDispatcher("/two");
//2.将报告对象发送给Tomcat
report.forward(request,response);
}
}
public class TwoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("TwoServlet ");
}
}
特征:
①在请求转发过程中,浏览器只发送一次请求。
②只能向Tomcat服务器申请调用当前网站下的资源文件。
request.getRequestDispatcher("/资源文件名");//不要写网站名
③在请求转发过程中,浏览器只发送了一个Http请求协议包。参与本次请求的所有Servlet共
享同一个请求协议包,因此这些Servlet接收的请求方式与浏览器发送的请求方式保持一致。
优点:
①无论本次请求涉及到多少个Servlet,用户只需要手动通过浏览器发送一次请求。
②Servlet之间的调用发生在服务端计算机上,节省服务端与浏览器之间往返次数,增加处理
服务速度。
9.多个Servlet之间数据共享实现方案
9.1 概述
数据共享:OneServlet工作完毕后,将产生数据交给TwoServlet来使用。
Servlet规范中提供四种数据共享方案:
①ServletContext接口
②Cookie
③HttpSession接口
④HttpServletRequest接口
9.2 ServletContext接口
来自于Servlet规范中的一个接口。在Tomcat中存在于servlet-api.jar中,在Tomcat中负责提供这个接口实现类。
如果两个Servlet来自于同一个网站,彼此之间通过网站的ServletContext实例对象来实现数据共享。
开发人员习惯将ServletContext对象称为全局作用域对象。
工作原理:每一个网站都存在一个全局作用域对象。这个全局作用域对象相当于一个Map,里面的数据以键值对的形式存储。在这个网站中OneServlet可以将一个数据存入到全局作用域对象中,当前网站中其他Servlet此时都可以从全局作用域对象得到这个数据进行使用。
全局作用域对象的生命周期:在Http服务器启动过程中,自动为当前网站在内存中创建一个全局作用域对象;在Http服务器运行期间时,一个网站只有一个全局作用域对象;在Http服务器运行期间,全局作用域对象一直处于存活状态;在Http服务器准备关闭时,负责将当前网站中全局作用域对象进行销毁处理。总之,全局作用域对象生命周期贯穿网站整个的运行期间。
命令实现: 【同一个网站】OneServlet将数据共享给TwoServlet
OneServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response){
//1.通过【请求对象】向Tomcat索要当前网站中【全局作用域对象】
ServletContext application = request.getServletContext();
//2.将数据添加到全局作用域对象作为【共享数据】
application.setAttribute("key1",数据)
}
}
TwoServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response){
//1.通过【请求对象】向Tomcat索要当前网站中【全局作用域对象】
ServletContext application = request.getServletContext();
//2.从全局作用域对象得到指定关键字对应数据
Object 数据 = application.getAttribute("key1");
}
}
public class OneServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.通过请求对象向Tomcat索要当前全局作用域对象
ServletContext application = request.getServletContext();
//2.将数据添加到全局作用域对象,作为共享数据
application.setAttribute("key1",100);
}
}
public class TwoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.通过请求对象向Tomcat索要当前网站全局作用域对象
ServletContext application = request.getServletContext();
//2.从全局作用域对象得到指定关键字对应的值
Integer money = (Integer) application.getAttribute("key1");//写成Integer防止空指针异常,int类型不能赋值null
}
}
9.3 Cookie
Cookie来自于Servlet规范中的一个工具类,存在于Tomcat提供的servlet-api.jar包中
如果两个Servlet来自于同一个网站,并且为同一个浏览器/用户提供服务,此时借助于Cookie对象进行数据共享。
Cookie存放当前用户的私有数据,在共享数据过程中提高服务质量。在现实生活场景中,Cookie相当于用户在服务端得到会员卡。
工作原理:用户通过浏览器第一次向MyWeb网站发送请求申请OneServlet,OneServlet在运行期间创建一个Cookie存储与当前用户相关数据;OneServlet工作完毕后,将Cookie写入到响应头交还给浏览器。浏览器收到响应包之后,将Cookie存储在浏览器的缓存中,一段时间之后,用户通过同一个浏览器再次向MyWeb网站发送请求申请TwoServlet时,浏览器需要无条件地将MyWeb网站之间推送过来的Cookie写入到请求头发送过去,此时TwoServlet在运行时,就可以通过读取请求头中的Cookie信息,得到OneServlet提供的共享数据。
实现命令: 同一个网站 OneServlet 与 TwoServlet 借助于Cookie实现数据共享
OneServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response){
//1.创建一个cookie对象,保存共享数据(当前用户数据)
Cookie card = new Cookie("key1","abc");
Cookie card1= new Cookie("key2","efg");
****cookie相当于一个map
****一个cookie中只能存放一个键值对
****这个键值对的key与value只能是String
****键值对中key不能是中文
//2.【发卡】将cookie写入到响应头,交给浏览器
response.addCookie(card);
response.addCookie(card1)
}
}
浏览器/用户<---------响应包 【200】【cookie: key1=abc; key2=eft】【处理结果】
浏览器向myWeb网站发送请求访问TwoServlet---->请求包 【url:/myWeb/two method:get】【请求参数:xxxx Cookie key1=abc;key2=efg】【】【】
TwoServlet{
public void doGet(HttpServletRequest request,HttpServletResponse resp){
//1.调用请求对象从请求头得到浏览器返回的Cookie
Cookie[] cookieArray = request.getCookies();
//2.循环遍历数据得到每一个cookie的key 与 value
for(Cookie card:cookieArray){
String key = card.getName(); 读取key "key1"
Strign value = card.getValue();读取value "abc"
//提供较好的服务。。。。。。。。
}
}
}
一个代码实例:通过会员卡点餐。
public class OneServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName,money;
//1.调用请求对象读取请求头参数信息
userName = request.getParameter("userName");
money = request.getParameter("money");
//2.开卡,设置cookie
Cookie card1 = new Cookie("userName",userName);
Cookie card2 = new Cookie("money",money);
//3.指定card2在客户端硬盘上存活一分钟
card2.setMaxAge(60);
//4.发卡,将cookie写入到响应头交给浏览器
response.addCookie(card1);
response.addCookie(card2);
//5.通知Tomcat将【点餐页面】内容写入到响应体交给浏览器(重定向)
response.sendRedirect("/myWeb/index_2.html");
}
}
public class TwoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int jiaozi_money = 30;
int miaotiao_money = 20;
int gaifan_money = 15;
String food,userName = null;
int money = 0,xiaofei = 0,balance = 0;
Cookie[] cookieArray = null;
PrintWriter out = response.getWriter();
response.setContentType("text/html;charset=utf-8");
Cookie newCard = null;
//1.读取请求头参数信息,得到用户点餐食物类型
food = request.getParameter("food");
//2.读取请求体中cookie
cookieArray = request.getCookies();
//3.刷卡消费
for(Cookie card:cookieArray){
String key = card.getName();
String value = card.getValue();
if("userName".equals(key)){
userName = value;
}else if("money".equals(key)){
money = Integer.valueOf(value);//将得到的字符串转为int
if("饺子".equals(food)){
if(jiaozi_money > money) {
out.print("用户" + userName + "余额不足,请充值");
}else{
newCard = new Cookie("money",(money - jiaozi_money)+"");//只能存储String类型
xiaofei = jiaozi_money;
balance = money - jiaozi_money;
}
}else if("面条".equals(food)){
if(miaotiao_money > money){
out.print("用户" + userName + "余额不足,请充值");
}else{
newCard = new Cookie("money",(money - miaotiao_money)+"");
xiaofei = miaotiao_money;
balance = money - miaotiao_money;
}
}else if("盖饭".equals(food)){
if(gaifan_money > money){
out.print("用户" + userName + "余额不足,请充值");
}else{
newCard = new Cookie("money",(money - gaifan_money)+"");
xiaofei = gaifan_money;
balance = money - gaifan_money;
}
}
}
}
//4.将用户会员卡返还给用户
response.addCookie(newCard);//注意之前的余额变化了,所以需要新建一个cookie返还给浏览器
//对之前的money那个cookie产生了覆盖
//5.将消费记录
out.print("用户" + userName + "本次消费" + xiaofei + "余额:" + balance);
}
}
Cookie的销毁时机:
①默认情况下,Cookie对象存放在浏览器的缓存中,因此只要浏览器关闭,Cookie对象就被
销毁掉。
②在手动设置情况下,可以要求浏览器将接收的Cookie存放在客户端计算机硬盘上,同时需
要指定Cookie在硬盘上的存活时间。在存活时间范围内,关闭浏览器、关闭客户端计算机、
关闭服务器,都不会导致Cookie被销毁。cookie.setMaxAge(存活时间,单位是s);
9.4 HttpSession接口
HttpSession接口来自于Servlet规范下的一个接口,存在于Tomcat中servlet-api.jar,其实现类由Http服务器提供。Tomcat提供实现类存在于servlet-api.jar。
如果两个Servlet来自于同一个网站,并且为同一个浏览器/用户提供服务,此时借助于HttpSession对象进行数据共享。
开发人员习惯将HttpSession接口修饰对象称为会话作用域对象。
(重要)HttpSession和Cookie的区别:
①存储位置不同。Cookie存放在客户端计算机(浏览器内存/硬盘);HttpSession存放在服务端
计算机内存。
②数据类型不同。Cookie对象存储共享数据类型只能是String;HttpSession对象可以存储任
意类型的共享数据Object。
③存储数据数量不同。一个Cookie对象只能存储一个共享数据;一个HttpSession对象使用
map集合存储共享数据,所以可以存储任意数量共享数据。
④参照物不同。Cookie相当于客户从服务端得到的会员卡;HttpSession相当于客户在服务端
的私人保险柜。
命令实现: 同一个网站(myWeb)下OneServlet将数据传递给TwoServlet
OneServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response){
//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
HttpSession session = request.getSession();
//2.将数据添加到用户私人储物柜
session.setAttribute("key1",共享数据)
}
}
浏览器访问/myWeb中TwoServlet
TwoServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response){
//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
HttpSession session = request.getSession();
//2.从会话作用域对象得到OneServlet提供的共享数据
Object 共享数据 = session.getAttribute("key1");
}
}
一个代码实例:将商品加入购物车。
public class OneServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String goodsName;
//1.调用请求对象,读取请求头参数,得到用户选择商品名
goodsName = request.getParameter("goodsName");
//2.调用请求对象,向Tomcat索要当前用户在服务端的私人储物柜
HttpSession session = request.getSession();
//3.将用户选购商品添加到当前用户私人存储柜
Integer goodsNum = (Integer)session.getAttribute(goodsName);//查看当前该商品有多少件
if(goodsNum == null){
session.setAttribute(goodsName,1);
}else {
session.setAttribute(goodsName,goodsNum+1);
}
}
}
public class TwoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//调用请求对象向Tomcat索要当前用户在服务端私人储物柜
HttpSession session = request.getSession();
//2.将session中所有的key读取出来,存放一个枚举类型
Enumeration goodsNames = session.getAttributeNames();//session中存了多个数据,一次性全部取出
while (goodsNames.hasMoreElements()){
String goodsName = (String)goodsNames.nextElement();
int goodsNum = (int)session.getAttribute(goodsName);//此处不会出现空指针异常,可用int
System.out.println("商品名称:" + goodsName + "商品数量:" + goodsNum);
}
}
}
在不同的浏览器打开网站时,Http服务器是如何识别这是哪个用户的,即Http服务器是如何将用户与HttpSession关联起来的?
通过Cookie来实现。JSESSIONID。并且这个cookie只能存储在浏览器的缓存中,不能自己
手动设置。
getSession()与getSession(false)的区别:
①getSession():如果当前用户在服务端已经拥有自己的私人储物柜,要求Tomcat将这个私人
储物柜进行返回;如果当前用户在服务端尚未拥有自己的私人储物柜,要求Tomcat为当前用
户创建一个全新的私人储物柜。
②getSession(false):如果当前用户在服务端已经拥有自己的私人储物柜,要求Tomcat将这
个私人储物柜进行返回;如果当前用户在服务端尚未拥有自己的私人储物柜,此时Tomcat返
回null。
HttpSession的销毁时机:
①用户与HttpSession关联时使用的Cookie只能存放在浏览器缓存中.
②在浏览器关闭时,意味着用户与他的HttpSession关系被切断
③由于Tomcat无法检测浏览器何时关闭,因此在浏览器关闭时并不会导致Tomcat将浏览器关
联的HttpSession进行销毁
④为了解决这个问题,Tomcat为每一个HttpSession对象设置【空闲时间】,这个空闲时间默
认30分钟,如果当前HttpSession对象空闲时间达到30分钟,此时Tomcat认为用户已经放弃
了自己的HttpSession,此时Tomcat就会销毁掉这个HttpSession
HttpSession空闲时间手动设置:在当前网站/web/WEB-INF/web.xml
9.5 HttpServletRequest接口
在同一个网站中,如果两个Servlet之间通过请求转发方式进行调用,彼此之间共享同一个请求协议包,而一个请求协议包只对应一个请求对象,因此Servlet之间共享同一个请求对象,此时可以利用这个请求对象在两个Servlet之间实现数据共享。
在请求对象实现Servlet之间数据共享功能时,开发人员将请求对象称为请求作用域对象。
命令实现: OneServlet通过请求转发申请调用TwoServlet时,需要给TwoServlet提供共享数据
OneServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response){
//1.将数据添加到【请求作用域对象】中attribute属性
request.setAttribute("key1",数据); //数据类型可以任意类型Object
//2.向Tomcat申请调用TwoServlet
request.getRequestDispatcher("/two").forward(req,response)
}
}
TwoServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response){
//从当前请求对象得到OneServlet写入到共享数据
Object 数据 = request.getAttribute("key1");
}
}
public class OneServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.将数据添加到请求作用域对象,作为共享数据
request.setAttribute("key1","Hello World");
//2.代替浏览器,向Tomcat索要TwoServlet来完成剩余任务
request.getRequestDispatcher("/two").forward(request,response);
}
}
public class TwoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//从同一个请求作用域对象得到OneServlet写入到共享数据
String value = (String)request.getAttribute("key1");
System.out.println(value);
}
}
PS:根据动力节点课程整理,如有侵权,联系删除。