本篇供个人学习使用,有问题欢迎讨论

多个Servlet来处理同一次请求方案

一、前提

1、一个 servlet 只负责实现一个功能

2、浏览器在一次请求时,只能请求一个资源文件

3、如果浏览器的请求需要由多个 Servlet 来协同完成,需要用户多次通过【手动提交请求】来完成任务,这样会降低用户的服务质量

4、方案分类

​ 只需要用户手动通过浏览器发送一次请求,就可以将与本次请求相关的 Servlet 依次调用

(1)重定向

(2)请求转发

二、重定向

1、原理

​ 在第一个 servlet 工作完毕后,将【第二个servelt 地址】推送给用户浏览器,由用户浏览器根据这个地址来【自动的】向第二个 servelt 发送请求

2、重定向涉及命令

response.sendRedirect(第二个servelt地址);

将一个地址写入到【响应头】中 location 浏览器接受到响应包之后,自动根据 location 地址发送第二次请求,这样好在避免用户多次手动发送请求

注意:重定向时需要从网站根目录名称开始写!

3、重定向特征

(1)发生位置:在客户端的浏览器上

(2)浏览器发送的请求次数:多次

(3)地址栏内容是否会发生变化:会发生变化,内容是浏览器第二次需要访问的资源地址

(4)重定向时,浏览器采用的请求方式:由于此时通过地址栏命令浏览器发送请求,所以浏览器采用请求方式一定是 GET

(5)重定向时,访问的资源文件范围:可以访问的是资源文件,可以是同一个网站的资源,也可以是其他网站的资源

4、重定向时的数据传递

login.jsp:

<form action="one.do" method="get">用户名:<input type="text" name="username" /><br>年龄:<input type="text" name="age" /><br><input type="submit" value="登录">
</form>

OneServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");String age = request.getParameter("age");System.out.println("username = " + username);System.out.println("age = " + age);//手动进行拼接response.sendRedirect("two.do?pname=" + username + "&page=" + age);
}

TwoServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String pname = request.getParameter("pname");String page = request.getParameter("page");System.out.println("pname ==== " + pname);System.out.println("page ==== " + page);response.getWriter().println("This is TwoServlet...");
}

点击按钮后进行跳转,注意看地址栏:

5、重定向时的数据传递的中文乱码问题解决

关于Servlet的中文乱码问题可以看我的博文Servlet出现中文乱码的问题

以上个例子为例,用中文提交时,存在着乱码问题:

注意:Tomcat9已经解决了此问题,这里我们针对的是Tomcat8及以下版本

OneServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");//如果是Tomcat8及以上版本的,则可不用写下行代码username = new String(name.getBytes("IS0-8859-1"),"UTF-8");//编码:打散username = URLEncoder.encode(username,"UTF-8");System.out.println("username = " + username);//手动进行拼接response.sendRedirect("two.do?pname=" + username + "&page=" + age);
}

TwoServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String pname = request.getParameter("pname");//解码:组装pname = URLDecoder.decode(pname,"UTF-8");//如果是Tomcat8及以上版本的,则可不用写下行代码pname = new String(pname.getBytes("IS0-8859-1"),"UTF-8");System.out.println("pname ==== " + pname);response.getWriter().println("This is TwoServlet...");
}

此时提交后已解决了中文乱码问题:

6、重定向方案适用场景

(1)添加功能 Servlet 调用:查询功能 Servlet

(2)删除功能 Servlet 调用:查询功能 Servlet

(3)更新功能 Servelt 调用:查询功能 Servlet

三、请求转发

1、原理

在第一个 servelt 工作完毕后,代替当前浏览器向 Tomcat 申请调用第二个 Servlet。Tomcat 在接受到申请之后,调用第二个 servelt 来完成本次请求中的剩余任务

2、请求转发涉及的命令

//1.创建一个资源申请报告对象
RequestDispatcher report = request.getRequestDispatcher("第二个servelt地址");
//2.将申请报告推送给Tomcat,同时将OneServlet拥有的request和response一并交给Tomcat
report.forward (request,response);
//3.Tomcat在接受到报告之后,就会调用第二个servelt来完成剩余任务

注意:请求转发时不能从网站根目录名称开始写!

3、请求转发时为什么将第一个Servelt中的request和response交给Tomcat

(1)Tomcat 在接受到请求后,需要调用第二个 Servlet

(2)Tomcat 此时需要为第二个 Servelt 提供运行时需要的【request】和【response】

(3)但是,本次请求是由第一个 Servelt 来发送的,没有对应的【请求协议包】,因此导致 Tomcat 在接受到请求后,不会创建【request】和【response】

(4)为了解决这个问题,需要将第一个 servlet 使用的【request】和【response】通过 Tomcat 交给第二个 servlet 来使用

4、请求转发特征

(1)发生位置:发生在服务端

(2)浏览器发送请求次数:浏览器只向服务端发送了一次请求

(3)地址栏内容是否会发生变化:由于请求转发发生在服务端,因此浏览器地址内容保持在第一次请求内容中

(4)调用资源文件范围:只能访问同一个访问内部的资源文件

(5)通过请求转发调用的 servlet 接受的请求方式:与浏览器第一次发送请求时,使用的请求方式

保持一致,参与同一次请求转发的所有 servlet 接受的请求方式是一样的

5、参与同一次请求转发的所有 servlet 之间如何进行数据共享

(1)提供共享数据

a、可以使用全局作用域对象,提供共享数据

//将一段共享数据保存到全局作用域对象
ServletContext application = request.getServletContext();
application.setAttribute("key1","mike");

b、可以使用会话作用域对象,提供共享数据

//将一段共享数据保存到当前来访的浏览器的HttpSession对象
HttpSession session = request.getSession();
session.setAttribute("key2","北京");

c、可以使用请求作用域对象,提供共享数据

//将一段共享数据保存当前的请求对象
request.setAttribute("key3",23);

(2)拿到共享数据

a、在全局作用域对象当中

ServletContext application = request.getServletContext();
String name = (String)application.getAttribute("key1");
System.out.println("TwoServlet从全局作用域对象得到共享数据" + name);

b、在会话作用域对象当中

HttpSession session = request.getSession();
string address = (String)session.getAttribute("key2");
System.out.println("TwoServlet从会话作用域对象得到共享数据" + address);

c、在请求作用域对象当中

Integer age = (Integer)request.getAttribute("key3");
System.out.println("TwoServlet从请求作用域对象得到共享数据" + age);

6、请求转发不适合场景

(1)添加功能 Servlet 调用:查询功能 Servlet

(2)删除功能 Servlet 调用:查询功能 Servlet

(3)更新功能 Servelt 调用:查询功能 Servlet

7、请求转发适合场景:查询 Servlet 调用 JSP 时

四、请求转发与重定向对比

1、请求转发

  • 浏览器只发出一次请求,收到一次响应
  • 请求所转发到的资源中可以直接获取到请求中所携带的数据
  • 浏览器地址栏显示的为用户所提交的请求路径
  • 只能跳转到当前应用的资源中

2、重定向

  • 浏览器发出两次请求,接收到两次响应
  • 重定向到的资源不能直接获取到用户提交请求中所携带的数据
  • 浏览器地址栏显示的为重定向的请求路径,而非用户提交请求的路径。也正因为如此,重定向的一个很重要作用是:防止表单重复提交
  • 重定向不仅可以跳转到当前应用的其它资源,也可以跳转到到其它应用中资源

3、请求转发与重定向的选择

  • 若需要跳转到其它应用,则使用重定向
  • 若是处理表单数据的 Servlet 要跳转到其它 Servlet,则需要选择重定向。为了防止表单重复提交
  • 若对某一请求进行处理的 Servlet 的执行需要消耗大量的服务器资源(CPU、内存),此时这个 Servlet 执行完毕后,也需要重定向
  • 若请求转发与重定向都可使用的话,尽量使用重定向,因为可以防止恶意刷新
  • 其它情况下,一般使用请求转发

五、RequestDispatcher

​ RequestDispatcher 是 javax.servlet 包下的一个接口,通过 HttpServletRequest 可以获取到

RequestDispatcher 的接口对象。顾名思义,该对象就是用于完成请求转发功能的。

1、forward()与include()

​ RequestDispatcher 接口中具有两个方法:forward() 与 include(),均可完成请求的转发。即可以将请求中所携带的参数由当前 Servlet 传递给下一下资源,如另一个Servlet。也就是说,这两个方法对于请求来说是相同的,都是请求转发。但它们的不同之处是响应,是标准响应输出流的开启时间不同。
TwoServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("Two request = " + request);System.out.println("Two response = " + response);
}

OneServlet:
forward()方式:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("One request = " + request);System.out.println("One response = " + response);request.getRequestDispatcher("two.do").forward(request,response);
}


include()方式:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("One request = " + request);System.out.println("One response = " + response);request.getRequestDispatcher("two.do").include(request,response);
}


从上图说明:无论是 forward() 还是 include(),对于请求来说,都是一样的,它们的不同点主要集中在响应对象。

2、代码测试及说明

(1)forward()

OneServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html");response.getWriter().println("OneServlet:forward() before...<br>");request.getRequestDispatcher("two.do").forward(request,response);response.getWriter().println("OneServlet:forward() after...<br>");
}

TwoServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.getWriter().println("TwoServlet Data...<br>");
}

输出结果:

void forward(ServletRequest request, ServletResponse response)
使用该方法,则当前的 Servlet 中只能进行业务处理,而不能向浏览器发送要显示的数据。因为请求还未完成,需要继续向前(forward),当请求完成后,服务器才会开启标准响应输出流,向输出流中写入数据。
该方法的响应对象,使用的是第二个资源的响应对象。即第二个资源向浏览器回送的响应数据。
不过,需要注意的是,在以上测试中的OneServlet与TwoServlet中均添加对于Response对象的输出语句,会发现这两个Servlet中所使用的Response对象为同一个ResponseFacade对象。

​ 那为什么在OneServlet中向输出流中的 print() 写入数据后,并不会显示到客户端浏览器?

​ 原因就是Response对象在OneServlet中创建了,但标准输出流并未开启。输出流的开启是在TwoServlet中进行的。

(2)include():

OneServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html");response.getWriter().println("OneServlet:include() before...<br>");request.getRequestDispatcher("two.do").include(request,response);response.getWriter().println("OneServlet:include() after...<br>");
}

TwoServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.getWriter().println("TwoServlet Data...<br>");
}

输出结果:

void include(ServletRequest request, ServletResponse response)
使用该方法,在将请求向后转发时,服务器会将标准响应输出流开启。当前Servlet可以向输出流中写入数据,并且服务器还会将要转向的资源的输出流中数据合并到当前的输出流中
该方法的响应对象,使用的是第一个资源的响应对象,即当前Servlet向浏览器回送的响应数据。
需要注意的是,在以上测试中的OneServlet与TwoServlet中均添加对于Response对象的输出语句,会发现OneServlet输出的是ResponseFacade对象,而TwoServlet输出的则是ApplicationHttpResponse 对象。
ApplicationHttpResponse是HttpServletResponse接口的实现类ResponseFacade的装饰者类,其增强了ResponseFacade类的功能。ApplicationHttpResponse底层完成的一个工作是,将当前的TwoServlet中的输出流中的数据合并到了OneServlet的标准输出流中。

3、总结

forward( )与include( )的区别,主要表现在标准输出流的开启时间不同

(1)forward()

​ forward这个单词表示的意思是“向前”,说明当前的请求还未结束,需要继续“向前”,所以服务器就不会在这里先打开标准输出流。所以此时写入到out中的数据是不会写入到客户端浏览器中的。
使用forward()方法的Servlet,其标准输出流还未开启。
对客户端的响应肯定不是使用forward( )方法的Servlet给出的。

(2)include()

​ include这个单词表示的意思是“包含”,说明当前的请求已经结束,可以对客户端进行响应了。其不仅将自己的数据写入到了标准输出流,还要将其它数据包含到自己的输出流中。
使用include()方法的Servlet,其标准输出流已经打开。
对客户端的响应是由使用include( )方法的Servlet给出的。

(3)结论

​ 在使用forward()进行请求转发时,使用forward()的Servlet不应向Response中写入数据,若要写入数据,则应使用include()进行转发

重定向与请求转发的具体讲解相关推荐

  1. JSP中的重定向和请求转发以及它们的区别

    我们先硬着头皮看一下重定向的定义: 重定向(Redirect): 客户端浏览器向Web应用服务器端发送一个请求,Web服务器端使用HttpServletResponse的sendRedirect()方 ...

  2. 3.相应重定向与请求转发的比较

    响应重定向与请求转发类似,但有下面的区别: (1)RequestDispatcher对象是一个Web资源的包装器,可以用来把当前请求转发到该资源.这种转发是服务器端控制权的转向,客户端发来的请求将交由 ...

  3. 分析:重定向和请求转发

    分析:重定向和请求转发 重定向 HttpServletResponse对象的sendRedirect(java.lang.String location)方法称作重定向. 如果location地址前面 ...

  4. 请求转发和重定向的区别_WEB之重定向和请求转发的区别

    一次重定向的过程 我的代码里面已经写好了,redirectAndFoward.jsp页面上有一个表单,表单重定向到redirectAndFowardTarget.jsp,那么这一次的重定向过程为: 1 ...

  5. 重定向与请求转发的区别及什么时候使用

    重定向与请求转发的区别 一 转发是服务器行为,重定向是客户端行为.为什么这样说呢,这就要看两个动作的工作流程: 转发过程:客户浏览器发送http请求-->web服务器接受此请求-->调用内 ...

  6. SpringMVC重定向与请求转发

    SpringMVC重定向与请求转发 一,请求转发 ①请求转发地址栏不会发生改变 ②请求转发只发送一次请求.能携带原有的参数 ③请求转发只可以在同一个服务器中进行转发 ④实际上视图解析器的转发本质也是请 ...

  7. java | (二十五)Servlet(1)req,resp,重定向,请求转发,数据共享

    今天(2021.9.24)开始学习一些有难度的知识了,如题 先安装和配置好Tomcat,具体下载和idea的配置可以参考 目录 开发步骤 Servlet对象生命周期 httpServletRespon ...

  8. 页面的跳转——请求重定向和请求转发

    目录 一.重定向(Redirect) 二.转发(Forward) 三.重定向和请求转发的区别 相同点 不同点 一.重定向(Redirect) 请求重定向是客户端行为.是指当浏览器请求一个URL时,服务 ...

  9. 相对地址与绝对地址的区别?请求重定向与请求转发的区别?jsp有哪九大内置对象?servlet如何获取session和application对象?

    目录 1.说说相对地址与绝对地址的区别? 2.说说请求重定向与请求转发的区别? 3.jsp有哪九大内置对象?servlet如何获取session和application对象? 1.说说相对地址与绝对地 ...

最新文章

  1. mangodb collection level operations
  2. 黄梅理工学校计算机,黄梅理工学校2021年有哪些专业
  3. 项目复审——Beta阶段
  4. [Redux/Mobx] Mobx的设计思想是什么
  5. py学习,列表,判断,循环
  6. K8S_Google工作笔记0011---通过二进制方式_部署etcd集群
  7. 2.7_single_link_list_单链表
  8. 利用hugo生成静态站点
  9. PHP - 主流开发框架 - 介绍
  10. Meterpreter 脚本列表
  11. java多个pdf合并为一个pdf,并通过feign下载
  12. fcpx字幕功能详细使用教程
  13. 凹凸世界服务器维护到几点,凹凸世界手游2021年7月21日版本更新停服维护公告_凹凸世界手游2021年7月21日更新了什么_菜鸟游戏网...
  14. 《用PS给照片换底》
  15. 【Simulink】常用模块知识总结
  16. C语言 一维数组(笔记)
  17. 时空召唤今天服务器维护吗,时空召唤11月15日维护更新预告 全新地图全面开放...
  18. 05.Beetl标签函数以及定界符、占位符介绍---《Beetl视频课程》
  19. 10款WordPress头像插件
  20. 计算机同心圆画法(计算机二级考题1)

热门文章

  1. 智能物流,让物流变得更加智能和高效
  2. 通用高校排课算法研究----前言
  3. 华科_图形学笔记_0201_认识图形系统
  4. 《个人相册》项目相册页面(HTML+CSS+JS)
  5. 【沃顿商学院学习笔记】领导力——Impact Investing:04 基于影响力投资效用与传统投资的研究效用及对比 Research of SRI utility and comparison
  6. LeetCode Java刷题笔记—297. 二叉树的序列化与反序列化
  7. 写给想去银行国企Java岗位的学习路线规划
  8. 应该和群还是独来独往
  9. 波特率是什么?(Baudrate)
  10. debian 升级linux内核,debian的成功升级内核