欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

对request的理解

程序员文章站 2022-07-14 20:19:43
...
对request的理解

(1)
页面一(base.jsp)
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
  <head>
    <base href="<%=basePath%>">
    <title>base.jsp</title>
  </head>
  <body>
    <form action="basetest/request.jsp">
    <%
     request.setAttribute("key","request");
    %>
    <input type="text" name="helloTest" value="helloTest">
    <br><input type="submit" value="提交">
   </form>
  </body>
</html>
页面二(request.jsp)
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
  <head>
    <base href="<%=basePath%>">
    <title>request.jsp</title>
  </head>
  <body>
    <%
     out.println(request.getAttribute("key"));
     Enumeration enumer=request.getAttributeNames();
     while(enumer.hasMoreElements())
     {
      out.println(enumer.nextElement());
     }
    %>
  </body>
</html>
页面一在request中用setAttribute放入一对象,在页面二中取不到打印结果为null
原因就在于request对象的创建过程,request和response对象是web容器中接收到一个对servlet(jsp的本质就是一个servlet)的请求时创建的,request中封装了用户的http请求信息,然后容器把这两个对象传递给servlet。
也就是说第一个页面中的request和第二个页面中的request是完全没有任何关系的由容器创建的两个request,页面间传递对象(不经过其它页面或servlet)还是用session,application吧。

(2)
request的作用范围是,用户请求的当前Web组件以及与当前Web共享同一个用户请求的其它web组件。
首先先来比较一下@include和jsp:includer的区别
我现在有三个文件request.jsp,includeTest.html,includeTest.jsp要包含其它两个页面,关键代码如下(页面body标签间的内容)
request.jsp
<fieldset>
   <legend>myself</legend>
  
   String tempstr="hello world";<br>
   <%String tempstr="hello world"; %><br>
  
   out.println(tempstr);<br>
   <%out.println(tempstr); %><br>
   Enumeration<br>
   <%
     Enumeration enumer=request.getAttributeNames();
     while(enumer.hasMoreElements())
     {
      out.println(enumer.nextElement());
      out.print("<br>");
     }
    %><br>
    pageContext.setAttribute("key","page(request.jsp)");<br>
   <%pageContext.setAttribute("key","page(request.jsp)");%><br>
    request.setAttribute("key","request(request.jsp)");<br>
   <%request.setAttribute("key","request(request.jsp)");%><br>
  </fieldset>
  <fieldset>
   <legend>includeTest.html(@include)</legend>
   <%@include file="includeTest.html"%>
  </fieldset>
  <fieldset>
   <legend>includeTest.html(jsp:include)</legend>
   <jsp:include page="includeTest.html"></jsp:include>
  </fieldset>
  <fieldset>
   <legend>includeTest.jsp(@include)</legend>
   <%@include file="includeTest.jsp"%>
  </fieldset>
  <fieldset>
   <legend>includeTest.jsp(jsp:include)</legend>
//先注释掉
   <%//<jsp:include page="includeTest.jsp"></jsp:include> %>  
  </fieldset>
includeTest.html
out.println(pageContext.getAttribute("key"));<br>
   <%out.println(pageContext.getAttribute("key")); %><br>
  
   out.println(request.getAttribute("key"));<br>
   <%out.println(request.getAttribute("key")); %><br>
  
    out.println(session.getAttribute("key"));<br>
   <%out.println(session.getAttribute("key")); %><br>
  
   out.println(application.getAttribute("key"));<br>
   <%out.println(application.getAttribute("key")); %><br>
  
    out.println(tempstr);<br>
   <%out.println(tempstr); %><br>
   Enumeration<br>
   <%
     enumer=request.getAttributeNames();
     while(enumer.hasMoreElements())
     {
      out.println(enumer.nextElement());
      out.print("<br>");
     }
    %><br>
includeTest.jsp页面的内容和includeTest.html的一摸一样

结果
myselfString tempstr="hello world";

out.println(tempstr);
hello world
Enumeration

pageContext.setAttribute("key","page(request.jsp)");

request.setAttribute("key","request(request.jsp)");

includeTest.html(@include)
out.println(pageContext.getAttribute("key"));
page(request.jsp)
out.println(request.getAttribute("key"));
request(request.jsp)
out.println(tempstr);
hello world
Enumeration
key

includeTest.html(jsp:include)
out.println(pageContext.getAttribute("key"));

out.println(request.getAttribute("key"));

out.println(tempstr);

Enumeration


includeTest.jsp(@include)
out.println(pageContext.getAttribute("key"));
page(request.jsp)
out.println(request.getAttribute("key"));
request(request.jsp)
out.println(tempstr);
hello world
Enumeration
key

includeTest2.jsp(jsp:include)
//注释掉了,空

先说@include
你如果和我一起创建的话你会发现includeTest.jsp页面已经报错说是tempstr,enumer变量未定义,现在先不用着急,咱们先发布到服务器上看看。
如果你访问这个request.jsp页面的时候你会发现一切正常没有报错。原因就在于jsp页面编译的时候遇到@include就直接把所要包含的页面的所有内容拿过来与当前页面融合为一个整体再去一起编译,无论他是要包含一个jsp页面还是一个html页面,所以html页面中的java代码也能照样解析。在包含的页面中主页面中的变量都可以访问到,当然你也可以在includeTest.html或includeTest.jsp中定义变量在request.jsp或includeTest.html或includeTest.jsp调用访问不过要定义好包含顺序(同理在这三个页面中不能变量重名,一个页面有个变量名a在其它页面中就不能有变量名为a,否则编译出错)。
怎么来证明上面这段话的正确性呢?
(1)@include进来的includeTest.jsp或includeTest.html页面都打印出了在request.jsp中放入到pageContext和request中的值。由pageContext的作用范围可以证明。
(2)查看tomcat work目录下有没有生成includeTest.java文件,你会发现没有(jsp:include就会生成)
(3)查看生成的servlet源代码。tomcat work目录下查看request.java你会发现里面包含着其他包含页面的源代码。这个证明更充分。

再说jsp:include
把上面request.jsp中的注释去掉直接访问的话你会发现报错:tempstr(enumer) cannot be resolved(变量无法解析)这就是jsp:include与@include的区别,它是先编译要包含的页面然后把编译后的在整体包过来,两个页面是独立编译的,所以变量就不能互访。两个页面是独立的你可以定义相同的变量名,但是被包含页面中你照样可以主页面中request中存储的对象。
includeTest2.jsp(jsp:include)
out.println(pageContext.getAttribute("key"));
null
out.println(request.getAttribute("key"));
request(request.jsp)

Enumeration
javax.servlet.include.request_uri
javax.servlet.include.context_path
javax.servlet.include.servlet_path
key

如何证明呢?
(1)pageContext的值没有打印出来为null。
(2)查看includeTest.html(jsp:include)显示的结果。你可以看到直接打印出的都是页面信息,如果你点击右键查看源代码你会发现java代码片段并没有解析还是源代码的形式,这是由于它是jsp:include是让包含的文件独立去解析,html后缀的为静态页面容器不会去编译直接包进来所以原来代码什么样包进来就是什么样。(你可能会问<%out.println(request.getAttribute("key")); %>这些内容为什么在页面上没有显示出来,"<"相当于html中的关键字表示标签的开始,html解析器无法解析这个标签所以这段代码就不能像普通文本那样显示出来了)。
(3)查看tomcat work目录下有没有生成includeTest.java文件,你会发现生成了
(4)查看生成的servlet源代码,request_jsp.java。找到解析jsp:include的那部分代码如下
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "includeTest.jsp", out, false);
JspRuntimeLibrary类位于tomcat Lib目录下的jasper.jar中,反编译include部分的源代码如下
  public static void include(ServletRequest request, ServletResponse response, String relativePath, JspWriter out, boolean flush)
    throws IOException, ServletException
  {
    if ((flush) && (!(out instanceof BodyContent))) {
      out.flush();
    }

    String resourcePath = getContextRelativePath(request, relativePath);
    RequestDispatcher rd = request.getRequestDispatcher(resourcePath);

    rd.include(request, new ServletResponseWrapperInclude(response, out));
  }
很明显的看到是一个转发,这也就是为什么request.jsp中放入request中对象在被包含的页面中还可以访问的真正原因。

现在咱们回到对开头第一句话的理解
“request的作用范围是,用户请求的当前Web组件以及与当前Web共享同一个用户请求的其它web组件。”
在这个例子中“其它的web组件”就是指@include和jsp:include包含进来的其它页面。
其实还有一个,那就是jsp:forward所指向的页面。
forward.jsp
out.println(pageContext.getAttribute("key"));<br>
   <%out.println(pageContext.getAttribute("key")); %><br>
  
   out.println(request.getAttribute("key"));<br>
   <%out.println(request.getAttribute("key")); %><br>
  
   String tempstr="hello world forward";<br>
   <%String tempstr="hello world forward"; %><br>
  
   out.println(tempstr);<br>
   <%out.println(tempstr); %><br>
  
   Enumeration<br>
   <%
    Enumeration enumer=request.getAttributeNames();
     while(enumer.hasMoreElements())
     {
      out.println(enumer.nextElement());
      out.print("<br>");
     }
    %><br>
结果
out.println(pageContext.getAttribute("key"));
null
out.println(request.getAttribute("key"));
request(request.jsp)
String tempstr="hello world forward";

out.println(tempstr);
hello world forward
Enumeration
javax.servlet.forward.request_uri
javax.servlet.forward.context_path
javax.servlet.forward.servlet_path
key
直接查看生成的servlet源代码,选取关键代码
import javax.servlet.jsp.JspFactory;
private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
PageContext pageContext  = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true);
PageContext _jspx_page_context = null;
_jspx_page_context = pageContext;
if (true) {
        _jspx_page_context.forward("forward.jsp");
        return;
}
由此可见其实还是一个转发,所以仍然可以获取request中的对象。