我们先回顾一下Servlet的工作原理,Servlet的工作原理跟小猪同学食堂就餐的过程很类似。小猪同学点了烤鸡腿(要奥尔良风味的),食堂窗口的服务员记下了菜单,想了想后厨的所有厨师,然后将菜单和餐盘交给专门制作烤鸡腿的厨师,这位大厨根据菜单制作出奥尔良烤鸡腿并放进餐盘,交给窗口服务员,服务员将做好的烤鸡腿交给小猪同学,小猪同学饱餐一顿后,菜单和餐盘就都被清理掉了,模拟情景的图示如图1所示。
■ 图1 Servlet工作原理模拟情景
上述过程对应到java中其实就是用户通过浏览器向Web服务器发出HTTP请求,服务器选择相应的Servlet响应浏览器的请求,并将响应结果返回给浏览器。服务器在选择相应Servlet的时候会出现一些问题,如果该Servlet无法完成本次请求,它会怎么处理这种情况呢?在Servlet中有两种机制可以帮助我们解决上述问题,Servlet工作原理解释如图2所示。
■ 图2 Servlet工作原理
如果厨师不会做这道菜怎么办呢?有两种解决方案,就是我们本节的内容请求转发与重定向,模拟情景如图3所示。
■ 图3 重定向和转发的由来
01、请求转发原理
如果小猪到饭店点了麻辣凉粉,饭店的服务员记下了菜单,把这道菜交给了面点师傅。虽然凉粉是淀粉类食品,可是这道菜面点师傅不会做,应该交给炒菜的师傅来完成这道菜,于是面点师傅将菜单还给服务员,让服务员去找炒菜的师傅。服务员知道自己搞错了之后立刻把菜单交给炒菜师傅,炒菜师傅根据菜单制作出了麻辣凉粉并放入盘中交给服务员,服务员再将做好的凉粉交给小猪同学。这种在同一个饭店更换厨师并且不需要顾客再次点菜的处理方式叫做请求转发,其模拟情景如图4所示。
■ 图4 请求转发模拟情景
用户通过访问Web浏览器提出请求,由Servlet引擎创建Servlet1实例以及request和response对象,然后调用Servlet1的service()函数响应用户请求,service方法读取请求内容,写入响应内容,其工作原理如图5所示。
■ 图5 Servlet工作原理
在执行service()方法时如果遇到了请求转发forward命令,说明当前Servlet处理不了用户的请求,就要立刻调整请求头为forward命令中请求的Servlet2,清空响应对象的响应体,然后返回到Servlet引擎,请求转发中执行service方法的工作原理解释如图6所示。
■ 图6请求转发的工作原理图示2
service函数执行完毕后返回,服务器将响应结果发送到Web浏览器中,请求转发中service方法执行完毕后的工作原理解释如图7所示。
■ 图7 请求转发的工作原理图示3
02、重定向原理
可是如果饭店里的厨师都不会做小猪同学点的菜该怎么办呢?我们接下来就介绍另一种方式。如果小猪到川菜馆点了一份寿司,服务员将菜单递给厨师之后大厨发现所有的厨师都不会做寿司,于是川菜师傅将菜单还给服务员并告诉他日料馆的地址,再由川菜馆的服务员告诉小猪川菜馆做不了寿司,他应该去吃货街的日料馆。知道自己找错地方之后小猪就来到吃货街找到日料馆向服务员点了一份寿司,经过点菜,做菜,上菜的流程之后小猪终于如愿吃到了寿司。这种顾客需要到别的饭店重新提出请求的方式叫做重定向,如图7和8所示。
■ 图8 重定向模拟情景1
■ 图9 重定向模拟情景2
用户通过访问Web浏览器提出请求,由Servlet引擎创建Servlet1实例以及request和response对象,然后调用Servlet1的service()函数响应用户请求,其工作原理如图10所示。
■图10 Servlet工作原理
但是若在service中执行到了sendRedirect重定向命令,说明当前Servlet响应不了用户的请求,需要清空响应体中已经写入的内容,将能够响应用户请求的Servlet2的地址写入响应体中,然后将结果返回至服务器,执行sendRedirect方法的工作原理如图11所示。
■ 图11 重定向工作原理1
浏览器接到包含重定向地址的响应信息后会自动重新提交请求,Servlet引擎创建Servlet2实例同时创建新的request和response对象,然后调用Servlet2的service()函数响应用户请求,request和response方法的工作原理如图12所示。
■ 图12 重定向工作原理2
浏览器接到包含重定向地址的响应信息后会自动重新提交请求,Servlet引擎创建Servlet2实例同时创建新的request和response对象,然后调用Servlet2的service()函数响应用户请求,新的Servlet引擎执行service方法的工作原理如图13所示。
■ 图13 重定向工作原理3
service方法读取请求信息,写入响应信息,执行完毕之后返回,由服务器将结果发送至浏览器。
03、请求转发和重定向
实现请求转发的方式:
(1)得到RequestDispatcher对象:RequestDispatcher dispatcher=
request.getRequestDispatcher("a.jsp");
(2)转发 dispatcher.forward (request,response);
实现重定向的方式:
重定向response.sendRedirect("a.jsp");
RequestDispatcher.forward方法只能在同一个Web应用程序内的资源之间转发请求。
sendRedirect方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
案例1: 中用判断三角形的三边是否满足构成三角形的条件来实现请求转发和重定向,通过Example1_b_triangle_judge.jsp页面输入三角形的三标,然后提交到相应的Servlet进行处理和逻辑的判断,在Servlet代码中获取来自JSP页面的三边数据信息,若三边不构成三角形或者输入的三边均小于0则会重定向到初始页面,即Example1_b_triangle_judge.jsp页面重新输入数据信息,若三边满足构成三角形的条件则会转发到Example1_c_triangle_judge_show.jsp页面,并在该页面中输出三边的边长和面积。
注意:
web.xml
<servlet>
<servlet-name>triangleServlet</servlet-name>
<servlet-class>com.programs.Example1_a_triangleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>triangleServlet</servlet-name>
<url-pattern>/triangle_judge</url-pattern>
</servlet-mapping>
Example1_a_triangleServlet.java
JSP页面提交的目的地址对应的Servlet需要与Web.xml文件中的<url-pattern>相对应,而不是<servlet-name>对应。
@WebServlet(name = "triangleServlet")
public class Example1_a_triangleServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String sidea = request.getParameter("sidea");
String sideb = request.getParameter("sideb");
String sidec = request.getParameter("sidec");
int sideA = Integer.parseInt(sidea);
int sideB = Integer.parseInt(sideb);
int sideC = Integer.parseInt(sidec);
if (sideA < 0 || sideB < 0 || sideC < 0 ||
(sideA + sideB <= sideC || sideB + sideC <= sideA || sideA + sideC <= sideB)) {
response.sendRedirect("Example1_b_triangle_judge.jsp");
} else {
RequestDispatcher dispatcher = request.getRequestDispatcher("Example1_c_triangle_judge_show.jsp");
dispatcher.forward(request, response);//请求转发
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
Example1_b_triangle_judge.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>三角形判断</title>
</head>
<body>
<form action="triangle_judge">
<p>使用三角形案例实现转发和重定向</p>
<b>输入边长a:</b><input type="text" name="sidea"><br>
<b>输入边长b:</b><input type="text" name="sideb"><br>
<b>输入边长c:</b><input type="text" name="sidec"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
Example1_c_triangle_judge_show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>符合三角形</title>
</head>
<body>
<h3>这是请求转发得到的界面</h3>
<p>输入的三角形三边满足构成三角形的条件</p>
<%
String sidea = request.getParameter("sidea");
String sideb = request.getParameter("sideb");
String sidec = request.getParameter("sidec");
%>
<p>三边分别为:<%= sidea%>、<%= sideb%>、<%= sidec%>
</p>
<%
int sideA = Integer.parseInt(sidea);
int sideB = Integer.parseInt(sideb);
int sideC = Integer.parseInt(sidec);
double p = (sideA + sideB + sideC) / 2.0;
double area = Math.sqrt(p * (p - sideA) * (p - sideB) * (p - sideC));
%>
其面积为<%= area%>
</body>
</html>
请求转发和重定向的案例页面显示如图14、15、16、17所示,当输入的三边满足构成三角形条件时,转发到显示页面并输出三角形各边信息和三角形的面积,若不满足构成三角形条件时,则重定向到初始页面中。
■ 图14 请求转发和重定向案例6_6初始化页面显示
■ 图15 请求转发和重定向案例6_6提交页面显示
■ 图16 请求转发和重定向案例6_6转发页面显示
■ 图17 请求转发和重定向案例6_6重定向页面显示
04、重定向与转发区别
第一:资源使用范围不一样。请求转发的转发对象只能是当前Web应用程序的服务器中的资源;重定向不仅可以在同一服务器中使用,还可以将请求重定向到其他Web服务器;
第二:请求响应的次数不一样,请求转发只需要一次请求与响应过程,重定向需要两次请求与响应过程;
第三:请求转发的URL地址栏是不变,因为只有一次请求与响应,重定向会改变地址栏,因为有两次请求与响应过程;
第四:请求转发的两个Servlet实例共用请求响应对象,重定向需要创建两次请求与响应对象。