servlet中RequestDispatcher源码解析及使用

servlet中RequestDispatcher源码解析及使用

文章目录

  • servlet中RequestDispatcher源码解析及使用
      • 一、简介
      • 二、RequestDispatcher
        • 2.1 RequestDispatcher获取
        • 2.2 源码
        • 2.3 转发方法
          • 2.3.1 forward
          • 2.3.2 include
          • 2.3.3 sendRedirect
      • 三、示例

一、简介

RequestDispatcher可以让客户端请求在服务端server中的各个servlet间转发处理。这里结合源码对RequestDispatcher进行介绍。

二、RequestDispatcher

RequestDispatcher接收客户端请求,并将它们发送到server中的其它资源(如servlet、html文件、JSP文件)。RequestDispatcher当作对指定路径或名称的服务资源的包装。

2.1 RequestDispatcher获取

RequestDispatcher是通过HttpServletRequest.getRequestDispatcher方法获取的,参数为指定的资源路径,如果路径是相对路径,则相对目录是当前servlet的。HttpServletRequest.getRequestDispatcher方法定义源码如下:

public RequestDispatcher getRequestDispatcher(String path);

2.2 源码

RequestDispatcher的核心方法是forward和include,这里把RequestDispatcher中定义的常量也列出来,源码如下:

package javax.servlet;
import java.io.IOException;
public interface RequestDispatcher {
    //forward方式下,来源URI名称(值在目标request中attribute中获取)
    static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";

    //forward方式下,来源context路径名称(值在目标request中attribute中获取)
    static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";

    //forward方式下,来源路径信息名称(值在目标request中attribute中获取)
    static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info";

    //forward方式下,来源servlet的servlet路径名称(值在目标request中attribute中获取)
    static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";

    //forward方式下,来源请求查询串名称(值在目标request中attribute中获取)
    static final String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";

    //include方式下,目标请求的URI名称(值在目标request中attribute中获取)
    static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";

    //include方式下,目标context路径名称(值在目标request中attribute中获取)
    static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";

    //include方式下,目标路径信息名称(值在目标request中attribute中获取)
    static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";

    //include方式下,目标servlet路径名称(值在目标request中attribute中获取)
    static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";

    //include方式下,目标查询串名称(值在目标request中attribute中获取)
    static final String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";

    //error方式下,传递的异常对象名称(值在目标request中attribute中获取)
    public static final String ERROR_EXCEPTION = "javax.servlet.error.exception";

    //error方式下,传递的异常类型名称(值在目标request中attribute中获取)
    public static final String ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type";

    //error方式下,传递的异常信息名称(值在目标request中attribute中获取)
    public static final String ERROR_MESSAGE = "javax.servlet.error.message";

    //error方式下,导致传递异常的请求URI名称(值在目标request中attribute中获取)
    public static final String ERROR_REQUEST_URI = "javax.servlet.error.request_uri";

    //error方式下,传递的发生错误的servlet名称(值在目标request中attribute中获取)
    public static final String ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name";

    //error方式下,传递的响应code名称(值在目标request中attribute中获取)
    public static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code";

    //在内部(浏览器地址不会改变)将请求从一个serlvet转发到另一个资源(servlet、jsp、html)处理
    public void forward(ServletRequest request, ServletResponse response)
        throws ServletException, IOException;

    //在响应请求中添加指定资源(servlet、jsp、html)
    public void include(ServletRequest request, ServletResponse response)
        throws ServletException, IOException;
}

关联的Dispatcher类型源,DispatcherType源码如下:

package javax.servlet;
public enum DispatcherType {
    //通过RequestDispatcher.forward方法请求
    FORWARD,
    //通过RequestDispatcher.include方法请求
    INCLUDE,
    //正常请求
    REQUEST,
    //异步请求
    ASYNC,
    //错误响应
    ERROR
}

2.3 转发方法

如前源码所示,转发的方法主要有forward和include,为了全面,这里也将HttpServletResponse.sendRedirect方法一并介绍。

2.3.1 forward

forward用于将客户端请求转发给其它server资源(servlet、jsp、html)处理,响应由指定server资源产生,浏览器地址不会改变。流程示意如下:

1请求
2转发
3响应
browser
oneServlet
twoServlet
2.3.2 include

include是在处理客户端请求时,同时添加其它server资源(servlet、jsp、html)的响应,浏览器地址不会改变。流程示意如下:

1请求
2转发
3响应
4响应
browser
oneServlet
twoServlet
2.3.3 sendRedirect

sendRedirect是位于HttpServletResponse中的方法,是直接将用户请求重置,由浏览器再次发起请求,浏览器地址会改变。流程示意图如下:

1请求
2响应
3再次主动
4再次响应
browser
oneServlet
twoServlet

三、示例

请求1的OneServlet.java定义如下:

package requestDispatcher;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

@WebServlet(name="oneServlet", urlPatterns = "/oneServlet")
public class OneServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("this is oneServlet. ");

        String type = Objects.toString(req.getParameter("type"), "redirect");
        RequestDispatcher requestDispatcher = req.getRequestDispatcher(req.getContextPath()+"/twoServlet");
        if("forward".equals(type)){
            //走RequestDispatcher的forward内部转发
            requestDispatcher.forward(req, resp);
        }else if("include".equals(type)){
            //走RequestDispatcher的include内部转发
            requestDispatcher.include(req, resp);
        }else {
            //走HttpServletResponse的sendRedirect转发
            resp.sendRedirect(req.getContextPath()+"/twoServlet");
        }
    }
}

请求2的TwoServlet.java定义如下:

package requestDispatcher;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name="twoServlet", urlPatterns = "/twoServlet")
public class TwoServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取来源servlet的servlet路径
        Object originServletPath = req.getAttribute(RequestDispatcher.FORWARD_PATH_INFO);
        System.out.println("originServletPath:"+originServletPath);
        resp.getWriter().write("this is towServlet.");
    }
}

操作结果:

请求:http://localhost:8080/oneServlet?type=forward
响应:this is towServlet.

请求:http://localhost:8080/oneServlet?type=include
响应:this is oneServlet. this is towServlet.

请求:http://localhost:8080/oneServlet?type=redirect
响应:his is towServlet.
同时:浏览器地址变为 http://localhost:8080/twoServlet

你可能感兴趣的:(servlet)