簡體   English   中英

為什么我不能使用<jsp:getproperty>沒有<jsp:usebean> ?</jsp:usebean></jsp:getproperty>

[英]Why I can't use <jsp:getProperty> without <jsp:useBean>?

假設有一個 servlet 有代碼:

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    foo.Person p = new foo.Person("Evan");
    req.setAttribute("person", p);

    RequestDispatcher view = req.getRequestDispatcher("/result.jsp");
    view.forward(req, resp);
}

,然后轉到result.jsp以打印給定名稱(Evan)。 這是它的外觀圖片(來源 Head First Servlets 和 JSP):

在此處輸入圖像描述

我知道<jsp:useBean>通過調用getAttribute()返回相同的 Person object - 因為它們在同一個請求中 scope 而另一方面, <jsp:getProperty>將調用findAttribute()以逐字地嘗試查找值 "person".. 的屬性並最終打印Evan

但是如果我不使用<jsp:useBean>怎么辦? 這是否意味着我無法在 scope請求中訪問“人”屬性? 我的意思是它仍然存在,即使我沒有使用<jsp:useBean>. 那么為什么我必須在<jsp:useBean>中的id<jsp:getProperty>中的name中具有相同的(“person”)? 簡單地刪除<jsp:useBean>會破壞我的程序。

知道<jsp:getProperty>調用findAttribute() ,如果有一個屬性(如attribute-name )將用作在范圍page>request>session>中查找屬性的參數,這不是更合乎邏輯嗎應用 為什么我必須“綁定”這兩個標簽: <jsp:useBean><jsp:getProperty>

你覺得下面的代碼怎么樣?

public class Main {
    public static void main(String[] args) {
        System.out.println(person);
    }
}

你一定已經猜對了,它不會編譯成功

現在,下面的代碼呢?

public class Main {
    public static void main(String[] args) {
        Person person = new Person();// Declaring person
        System.out.println(person);
    }
}

當然,它會編譯成功1因為現在編譯器person是什么了。

同樣,使用

<jsp:getProperty name="person" property="name">

沒有將person聲明為

<!-- Declaring person -->
<jsp:useBean id="person" class="foo.Person" scope="request" />

不會編譯成功


1 假設Person.class在那里。

TL;DR:您應該記住,您需要將<jsp:getProperty><jsp:useBean>一起使用,因為規范是這樣說的。 <jsp:useBean>需要將 bean 引入 JSP 處理器, <jsp:getProperty>才能使用它。

更長的解釋:

為什么我不能在沒有<jsp:useBean>的情況下使用<jsp:getProperty> > ?

因為它們“在某種程度上”被設計為一起工作。 我不知道為什么會這樣決定(只有 JSP 規范的設計者可以回答這個問題),但規范本身對<jsp:getProperty>有這樣的說法:

以該名稱命名的 object 必須已使用 jsp:useBean 操作或具有關聯的 VariableInfo 條目的自定義操作“引入”到 JSP 處理器。 如果沒有以這種方式引入 object,則建議(但不是必需)容器實現引發翻譯錯誤,因為頁面實現違反規范。

我說“有點”旨在協同工作,因為在某些情況下,您可以使用<jsp:getProperty>而不使用<jsp:useBean> ,但您必須配置 JSP 處理器以忽略 JSP.5.3 規范規則(對於允許那)。

這不是很清楚,所以讓我們看看一些代碼會發生什么。

我有以下 JSP:

-------------------------------------------------------------------
<jsp:useBean id="person" class="test.Person" scope="application" />
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<jsp:getProperty name="person" property="name" />
-------------------------------------------------------------------

我使用了這些分隔符,以便以后可以在 JSP 生成的 servlet 中找到它們,它們會生成以下代碼:

  out.write("\t\t-------------------------------------------------------------------\r\n");
  out.write("\t\t");
  test.Person person = null;
  synchronized (application) {
    person = (test.Person) _jspx_page_context.getAttribute("person", javax.servlet.jsp.PageContext.APPLICATION_SCOPE);
    if (person == null){
      person = new test.Person();
      _jspx_page_context.setAttribute("person", person, javax.servlet.jsp.PageContext.APPLICATION_SCOPE);
    }
  }
  out.write("\r\n");
  out.write("\t\t+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n");
  out.write("\t\t");
  out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((test.Person)_jspx_page_context.findAttribute("person")).getName())));
  out.write("\r\n");
  out.write("\t\t-------------------------------------------------------------------\r\n");

如果您查看<jsp:getProperty>您可以看到它對test.Person進行了強制轉換:

org.apache.jasper.runtime.JspRuntimeLibrary.toString((((test.Person)_jspx_page_context.findAttribute("person")).getName()))

但那是從哪里來的呢? 在您的<jsp:getProperty>中,您指定了一個 bean 名稱 ( person ) 和一個屬性名稱 ( name ),但沒有指定 class。 所以這些屬性只會導致findAttribute("person")getName() class 是從哪里取來的? 答案是,之前對<jsp:useBean>的調用在 JSP 處理器中引入了這個。

所以你必須調用<jsp:useBean>來在 JSP 處理器中引入 bean,這樣當處理器看到<jsp:getProperty>時就知道它在處理什么。 所以基本上, <jsp:useBean>定義它,然后<jsp:getProperty>使用它。 如果你不調用<jsp:useBean><jsp:getProperty>將嘗試使用未定義的東西,JSP 處理器會抱怨,你會得到一個異常:

jsp:獲取名稱為“人”的 bean 的屬性。 之前沒有按照 JSP.5.3 引入名稱

但是,如果您閱讀規格,它會說:

[...] 建議(但不是必須)使用容器實現來引發翻譯錯誤 [...]

If you use Tomcat, for example, there is a org.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY system property that controls the requirement to have the object used in <jsp:getProperty> to be previously "introduced" to the JSP processor (基本上,是否執行 JSP.5.3 規則)。 例如,請參閱此Tomcat 文檔頁面

因此,如果我使用以下系統變量啟動 Tomcat 服務器:

-Dorg.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY=false

然后我可以在沒有<jsp:useBean>的情況下使用<jsp:getProperty> ,前提是我以其他方式在 SCOPE 中引入person Bean(例如從帶有request.setAttribute()session.setAttribute()的 servlet 或application.setAttribute() ) 中引入。 application.setAttribute()以便<jsp:getProperty>可以執行pageContext.findAttribute()並查找名為person的 bean 並找到它。

如果您使用該系統屬性,則<jsp:getProperty>標記生成的 output 會更改。 它不再依賴於<jsp:useBean>並且演員表被移除:

out.write("\t\t+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n");
      out.write("\t\t");
      out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty(_jspx_page_context.findAttribute("person"), "name")));
      out.write("\r\n");
      out.write("\t\t-------------------------------------------------------------------\r\n");

如果有人對所有這些混亂如何展開感興趣,那么要查看的類(對於 Tomcat 服務器)是: org.apache.jasper.compiler.Validatororg.apache.jasper.compiler.Generator

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM