[英]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.Validator
和org.apache.jasper.compiler.Generator
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.