RequestDispatcher
由Servlet容器创建的一个WEB资源的包装器,可以用来把当前的request传递到该资源,或者把新的资源包括到当前响应中。
方法
void forward(ServletRequest request, ServletResponse response):将请求从一个servlet转发到另一个资源(servlet,jsp或HTML文件)。此方法允许一个servlet对请求进行初步处理,并使另一个资源生成响应。
如下图,Servlet1将请求转发给Servlet2,但是可以做相关的初步处理。如果Servlet1做相关的响应,并不会出现在客户端上,将会被丢弃。
void include(ServletRequest request, ServletResponse response):包含响应中的某个资源(servlet,jsp或HTML文件)的内容。事实上,此方法支持编程式服务器端的包含。
如下图,相当于Servlet1包含了Servlet2的服务,两者对服务器的响应都会反馈给客户。
示例代码
HTML文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="s1">Dispatcher-forward测试</a><br/>
<a href="s3">Dispatcher-include测试</a>
</body>
</html>
web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>Dispatcher</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>s1</servlet-name>
<servlet-class>com.li.servlet.forward.Servlet1</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>com.li.servlet.forward.Servlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s2</servlet-name>
<url-pattern>/s2</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>s3</servlet-name>
<servlet-class>com.li.servlet.include.Servlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s3</servlet-name>
<url-pattern>/s3</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>s4</servlet-name>
<servlet-class>com.li.servlet.include.Servlet4</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s4</servlet-name>
<url-pattern>/s4</url-pattern>
</servlet-mapping>
</web-app>
forward示例
Servlet1.java
package com.li.servlet.forward;
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;
public class Servlet1 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet1 doGet!");
resp.setContentType("text/html;charset=UTF-8");
/*此语句并不会被输出,因为请求转发给了s2,此响应将被丢弃
*/
resp.getWriter().write("Servlet1<br/>");
/*将请求转发给s2,使用的是相对路径,可以使用斜杠来表示不适用当前的工程目录*/
RequestDispatcher rd=req.getRequestDispatcher("s2");
req.setAttribute("test", Math.random());
/*调用forward方法*/
rd.forward(req, resp);
}
}
Servlet2.java
package com.li.servlet.forward;
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;
public class Servlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet2 doGet!");
/*
* 我们并没有在此设置resp的ContentType,但是我们在Servlet1中已经设置过,
* 在这里输出中文,以此观察响应对象是否被带过来。(实际上会被带过来,我们在此处并不需要再设置)
*/
double d=(Double)req.getAttribute("test"); //返回类型为Object类型,强制转换
resp.getWriter().write("test:"+d+"<br/>");
resp.getWriter().write("Servlet2你好<br/>");
}
}
include示例
Servlet3.java
package com.li.servlet.include;
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;
public class Servlet3 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet3 doGet!");
resp.setContentType("text/html;charset=UTF-8");
/*此语句会被响应出来,相当于s4被包含进来,应理解包含的意思*/
resp.getWriter().write("<strong>Servlet3</strong><br/>");
/*将请求转发给s4,使用的是相对路径,可以使用斜杠来表示不适用当前的工程目录*/
RequestDispatcher rd=req.getRequestDispatcher("s4");
/*调用include方法*/
rd.include(req, resp);
/*再接收s4设置的数据*/
double d=(Double)req.getAttribute("test"); //返回类型为Object类型,强制转换
resp.getWriter().write("test:"+d+"<br/>");
}
}
Servlet4.java
package com.li.servlet.include;
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;
public class Servlet4 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet4 doGet!");
/*设置值,回传给s3*/
req.setAttribute("test", Math.random());
resp.getWriter().write("Servlet4你好<br/>");
}
}
使用请求转发加载不出目的页面CSS文件的解决方法
当我们请求转发的目的页面是HTML文档或者JSP服务页面时,可能会出现一种情况,那就是页面的CSS文件或JS文件没有加载进去,那么这是上面问题呢?实际上这是路径的问题。
例如,假定我们的项目名称为:Store,当我们进入一个Servlet时(此Servlet的url-pattern为:do/servlet),重定向的目的JSP为:index.jsp。
该JSP页面中有以下引用:
<link rel="stylesheet" type="text/css" href="../../css/style.css" />
<link rel="stylesheet" type="text/css" href="../../css/shopping-mall-index.css" />
<script type="text/javascript" src="../../js/jquery.js"></script>
<script type="text/javascript" src="../../js/vin.js"></script>
在Servlet中的请求转发为:
request.getRequestDispatcher("../index.jsp").forward(request, response);
那么这样CSS和JS文件是加载不出来的,我们如果使用浏览器开发者工具查看,能发现这些文件报404错误,熟悉的人都知道这是什么错误,那么是什么文件没找到呢?有以下文件未找到:
http://localhost:8080/css/style.css
http://localhost:8080/css/shopping-mall-index.css
http://localhost:8080/js/jquery.js
http://localhost:8080/js/vin.js
问题分析:上面的URL中没有包含我们项目的名称,我们知道,请求转发地址栏不会改变(地址栏为http://localhost:8080/Store/do/servlet),而 href=”../../css/style.css” 此路径是相对于地址栏的路径,因而,实际上引用到的文件是 http://localhost:8080/css/style.css。
问题解决:把引用文件的路径改为两种的一种即可:
href="../css/style.css"
href="/Store/css/style.css"