小言_互联网的博客

JavaWeb核心技术系列教程(14)——请求转发与请求包含

242人阅读  评论(0)

C语言自学完备手册(33篇)

Android多分辨率适配框架

JavaWeb核心技术系列教程

HTML5前端开发实战系列教程

MySQL数据库实操教程(35篇图文版)

推翻自己和过往——自定义View系列教程(10篇)

走出思维困境,踏上精进之路——Android开发进阶精华录

讲给Android程序员看的前端系列教程(40集免费视频教程+源码)


版权声明

  • 本文原创作者:谷哥的小弟
  • 作者博客地址:http://blog.csdn.net/lfdfhl

概述

假若客户端浏览器发起的请求很复杂,单独一个Servlet不能够完成业务处理需要其它Servlet协同。此时,需在当前Servlet中调用其它Servlet的service( )方法协助处理。但是,自Servlet 2.1开始不能在Servlet中调用其它Servlet的service( )方法。在此情况下,我们可使用请求分发器RequestDispatcher实现请求转发和请求包含。

RequestDispatcher接口

在此,介绍RequestDispatcher的获取方式及其核心方法。

RequestDispatcher获取方式

方式一:通过ServletRequest的getRequestDispatcher( )获取

public RequestDispatcher getRequestDispatcher(String path)

方式二:通过ServletContext的getRequestDispatcher( )获取

public RequestDispatcher getRequestDispatcher(String path)

在以上两个方法中参数path表示目标Web资源的路径,该参数必须以代表当前Web应用的根目录的/开头。

RequestDispatcher核心方法

RequestDispatcher中接口中定义了两个非常核心的方法forward( )和include( )详解如下。

forward( )

 public void forward(ServletRequest request, ServletResponse response)throws ServletException, IOException

该方法用于将请求从当前Web资源(源组件)传递给另外一个Web资源(目标组件)。也就是说:当前Web资源(源组件)中对请求做初步处理后再将请求传递给其它Web资源(目标组件)进行响应。请注意:该方法 必须在响应提交给客户端之前被调用,否则将抛出IllegalStateException异常。

通常,我们使用forward( )实现请求转发。

include( )

public void include(ServletRequest request, ServletResponse response)throws ServletException, IOException

该方法用于将其它Web资源(目标组件)作出的响应包含到当前Web资源(源组件)中。

通常,我们使用include( )实现请求包含。

请求转发和请求包含的特点

  • 源组件和目标组件处理的是同一个请求,两者共享同一个ServletRequest对象和同一个ServletResponse对象。
  • 目标组件可为Servlet、HTML、或者JSP。

请求转发示例

示例1

在该示例中,我们在第一个Servlet中对用户请求作出响应后再将请求转发至另外一个Servlet。

index.html代码如下:

<!DOCTYPE html>
<!-- 本文作者:谷哥的小弟-->
<!-- 博客地址:https://blog.csdn.net/lfdfhl-->
<html>
	<head>
		<meta charset="utf-8">
		<title>index</title>
	</head>
	<body>
	    <h2 align="center" style="color: red;">本文作者:谷哥的小弟</h2>
		<h2 align="center" style="color: red;">博客地址:http://blog.csdn.net/lfdfhl</h2>
	</body>
</html>

index.html页面如下:

web.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>ServletRequestDispatcher01</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	<servlet>
		<servlet-name>testForwardServlet1</servlet-name>
		<servlet-class>cn.com.TestForwardServlet1</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>testForwardServlet1</servlet-name>
		<url-pattern>/testForwardServlet1</url-pattern>
	</servlet-mapping>
	<servlet>
		<servlet-name>testForwardServlet2</servlet-name>
		<servlet-class>cn.com.TestForwardServlet2</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>testForwardServlet2</servlet-name>
		<url-pattern>/testForwardServlet2</url-pattern>
	</servlet-mapping>
</web-app>

TestForwardServlet1如下:

package cn.com;

import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 本文作者:谷哥的小弟 
 * 博客地址:http://blog.csdn.net/lfdfhl
 * 
 * 请求转发forward( )示例
 */
public class TestForwardServlet1 extends HttpServlet {
	
	private static final long serialVersionUID = 2093382837605569304L;

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=UTF-8");
		//将数据存储至HttpServletRequest对象中
		request.setAttribute("country", "中华人民共和国");
		//获取RequestDispatcher
		RequestDispatcher requestDispatcher = request.getRequestDispatcher("/testForwardServlet2");
		//请求转发
		requestDispatcher.forward(request, response);
	}
	
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	}
}

TestForwardServlet2如下:

package cn.com;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 本文作者:谷哥的小弟 
 * 博客地址:http://blog.csdn.net/lfdfhl
 * 
 * 请求转发forward( )示例
 */
public class TestForwardServlet2 extends HttpServlet {
	private static final long serialVersionUID = 2199147094057707867L;
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=UTF-8");
		///从HttpServletRequest对象中获取数据
		String country = (String) request.getAttribute("country");
		//将数据返回至客户端浏览器
		response.getWriter().write(country);
	}
	
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	}
}

结果如下:

示例2

在实际开发中,经常将请求转发和Referer头字段结合起来使用。例如:网站期望用户在下载页面浏览广告再点击下载超链接而不是直接下载资源。所以,假若用户企图直接下载资源时将其重定向至下载页面;这也常被称为"防盗链"。

index.html代码如下:

<!DOCTYPE html>
<!-- 本文作者:谷哥的小弟-->
<!-- 博客地址:https://blog.csdn.net/lfdfhl-->
<html>
	<head>
		<meta charset="utf-8">
		<title>index</title>
	</head>
	<body>
	    <h2 align="center" style="color: red;">本文作者:谷哥的小弟</h2>
		<h2 align="center" style="color: red;">博客地址:http://blog.csdn.net/lfdfhl</h2>
	</body>
</html>

index.html页面如下:

download.html代码如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>forward</title>
	</head>
	<body>
	    <h1>请大家多看广告,支持本站</h1>
	    <h1>这里是一个关于网购的广告</h1>
		<a href="/ServletRequestDispatcher02/downloadServlet">点击此处下载</a>
		<h1>这里是一个关于汽车的广告</h1>
		<h1>这里是一个关于楼盘的广告</h1>
	</body>
</html>

download.html页面如下:

DownloadServlet如下:

package cn.com;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 本文作者:谷哥的小弟 
 * 博客地址:http://blog.csdn.net/lfdfhl
 * 
 * 利用Referer请求头实现防盗链
 * 
 */
public class DownloadServlet extends HttpServlet {
	
	private static final long serialVersionUID = 4444457621093648047L;

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter printWriter = response.getWriter();
		// Referer请求头的值
		String referer = request.getHeader("referer");
		System.out.println("referer="+referer);
		// 获取服务器名称
		String serverName = "http://" + request.getServerName();
		System.out.println("serverName="+serverName);
		// 判断referer头是否为空,如果不为空再判断referer是否以serverName开始
		if (referer != null && referer.startsWith(serverName)) {
			// 下载
			printWriter.println("Downloading , Please Wait.....");
		} else {
             // 获取请求转发器RequestDispatcher
			RequestDispatcher requestDispatcher = request.getRequestDispatcher("/download.html");
			// 非法下载时将请求转发至download.html页面
			requestDispatcher.forward(request, response);
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

测试方式如下:

  • 1、部署Web应用至Tomcat
  • 2、直接访问downloadServlet,地址如下
    http://localhost:8080/ServletRequestDispatcher02/downloadServlet
    转发至download.html页面
  • 3、点击download.html页面中下载的超链接开始执行下载

web.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>downloadServlet</servlet-name>
    <servlet-class>cn.com.DownloadServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>downloadServlet</servlet-name>
    <url-pattern>/downloadServlet</url-pattern>
  </servlet-mapping>
</web-app>

请求包含示例

相对于请求转发而言,请求包含不是特别容易理解。别急,我们先来说说什么是"包含"。老板让我去超市买包烟,去菜市场买大白菜。我太忙,为了省时间,我去买烟的时候给小王说:你去菜市场买大白菜,待会儿给我。当我买烟回来之后,再拿着小王帮忙买的大白菜一起给老板。也就是说:在我返回给老板的劳动成果里实际上包含了小王的工作量!

类似地:某个Web资源响应至客户端服务器的内容包含了其它Web资源的响应;这求是请求包含。请看下面的例子。

index.html代码如下:

<!DOCTYPE html>
<!-- 本文作者:谷哥的小弟-->
<!-- 博客地址:https://blog.csdn.net/lfdfhl-->
<html>
	<head>
		<meta charset="utf-8">
		<title>index</title>
	</head>
	<body>
	    <h2 align="center" style="color: red;">本文作者:谷哥的小弟</h2>
		<h2 align="center" style="color: red;">博客地址:http://blog.csdn.net/lfdfhl</h2>
	</body>
</html>

index.html页面如下:

TestIncludeServlet1如下:

package cn.com;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 本文作者:谷哥的小弟 
 * 博客地址:http://blog.csdn.net/lfdfhl
 * 
 * 请求包含include( )使用示例
 */
public class TestIncludeServlet1 extends HttpServlet {

	private static final long serialVersionUID = -5480067421143433992L;

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		//响应内容
		PrintWriter printWriter = response.getWriter();
		printWriter.write("四川"+ "<br/>");
		// 获取请求转发器RequestDispatcher
		RequestDispatcher requestDispatcher = request.getRequestDispatcher("/testIncludeServlet2?username=zhouxingxing");
		printWriter.println("start including" + "<br/>");
		// 转发至testIncludeServlet2
		requestDispatcher.include(request, response);
		printWriter.println("end including" + "<br/>");
	}
	
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	}
}

TestIncludeServlet2如下:

package cn.com;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 本文作者:谷哥的小弟 
 * 博客地址:http://blog.csdn.net/lfdfhl
 * 
 *  请求包含include( )使用示例
 */
public class TestIncludeServlet2 extends HttpServlet {
	
	private static final long serialVersionUID = -6353109083643162025L;

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		//响应内容
		PrintWriter printWriter = response.getWriter();
		printWriter.println("成都" + "<br/>");
		//从ServletRequest中获取参数
		printWriter.println("RequestURI=" + request.getRequestURI() + "<br/>");
		printWriter.println("username=" + request.getParameter("username") + "<br/>");
	}
	
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	}
}

结果如下:

从这个示例中可以看出:返回至客户端浏览器的内容既有TestIncludeServlet1的响应也有TestIncludeServlet2 的响应。

请求转发与请求包含总结

  • 重定向时浏览器中的地址栏会发生变化,但是请求转发时浏览器中地址栏不会发生改变。从本质上来讲:重定向是两次不同的请求,而请求转发只向服务端的发送了一次请求由服务端的内部实现请求的跳转。

  • 重定向可以跳转到应用的外部,而请求转发的范围只能是应用的内部

  • 请求转发可利用request.setAttribute()将数据传递到下一个Servlet且下一个Servlet可用request.getAttribute()取出数据;但是重定向不可以也没有道理这么做。至于为什么,请参考第一点。


转载:https://blog.csdn.net/lfdfhl/article/details/101645013
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场