ทำไมฉันไม่สามารถใช้ <jsp: getProperty> โดยไม่มี <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()
- ตั้งแต่พวกเขาอยู่ในที่เดียวกันขอบเขตการร้องขอ ในขณะที่ในด้านอื่น ๆ ที่<jsp:getProperty>
จะเรียกfindAttribute()
ที่แท้จริงพยายามที่จะหาแอตทริบิวต์ของมูลค่า "บุคคล" .. และในที่สุดก็พิมพ์อีวาน
แต่ถ้าไม่ได้ใช้<jsp:useBean>
ล่ะ? หมายความว่าฉันไม่สามารถเข้าถึงแอตทริบิวต์ "บุคคล" ตามคำขอขอบเขตใช่หรือไม่ ฉันหมายความว่ามันจะยังคงอยู่ที่นั่นแม้ว่าฉันจะไม่ได้ใช้<jsp:useBean>.
แล้วทำไมฉันต้องมีค่าเดียวกัน("คน") ทั้งในidใน<jsp:useBean>
และชื่อข้างใน<jsp:getProperty>
? การลบอย่างง่าย<jsp:useBean>
จะทำให้โปรแกรมของฉันแตก
รู้ว่า<jsp:getProperty>
สายfindAttribute()
จะไม่ได้เป็นตรรกะมากขึ้นถ้ามีแอตทริบิวต์เดียว (เช่นแอตทริบิวต์ชื่อ ) ที่จะนำมาใช้เป็นข้อโต้แย้งที่จะหาแอตทริบิวต์ในขอบเขตหน้า> คำขอ> เซสชั่น> แอปพลิเค ? ทำไมฉันต้อง "ผูก" สองแท็ก: <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:getProperty>
โดยไม่ต้อง<jsp:useBean>
?
เนื่องจากพวกเขา "ค่อนข้าง" ออกแบบมาเพื่อทำงานร่วมกัน ฉันไม่รู้ว่าทำไมถึงตัดสินใจแบบนั้น (เฉพาะนักออกแบบของข้อกำหนด JSP เท่านั้นที่สามารถตอบได้) แต่ข้อมูลจำเพาะนั้นมีไว้เพื่อพูดถึง<jsp:getProperty>
:
อ็อบเจ็กต์ที่ตั้งชื่อตามชื่อต้องได้รับการ“ แนะนำ” ให้กับโปรเซสเซอร์ JSP โดยใช้แอ็คชัน jsp: useBean หรือแอ็คชันแบบกำหนดเองที่มีรายการ VariableInfo ที่เกี่ยวข้องสำหรับชื่อนี้ หากไม่ได้นำออบเจ็กต์มาใช้ในลักษณะนี้ขอแนะนำให้ใช้คอนเทนเนอร์ (แต่ไม่จำเป็น) เพื่อเพิ่มข้อผิดพลาดในการแปลเนื่องจากการใช้งานเพจละเมิดข้อกำหนด
ฉันพูดว่า "ค่อนข้าง" ออกแบบมาเพื่อทำงานร่วมกันเพราะในบางกรณีคุณสามารถใช้ได้<jsp:getProperty>
โดยไม่ต้อง<jsp:useBean>
แต่คุณต้องกำหนดค่าตัวประมวลผล JSP ให้ละเว้นกฎข้อกำหนด JSP.5.3 (สำหรับเซิร์ฟเวอร์ที่อนุญาต)
สิ่งนี้ยังไม่ชัดเจนดังนั้นเรามาดูกันว่าเกิดอะไรขึ้นกับโค้ดบางส่วน
ฉันมี JSP ต่อไปนี้:
-------------------------------------------------------------------
<jsp:useBean id="person" class="test.Person" scope="application" />
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<jsp:getProperty name="person" property="name" />
-------------------------------------------------------------------
ฉันใช้ตัวคั่นเหล่านั้นเพื่อที่ฉันจะสามารถค้นหาได้ในภายหลังใน servlet ที่สร้างโดย JSP ซึ่งส่งผลให้เกิดรหัสนี้:
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
) แต่ไม่มีคลาส ดังนั้นคุณลักษณะเหล่านั้นเพียง แต่ส่งผลในและจากนั้นในfindAttribute("person")
getName()
ชั้นเรียนมาจากไหน? และคำตอบคือการเรียกก่อนหน้านี้เพื่อ<jsp:useBean>
แนะนำสิ่งนี้ในโปรเซสเซอร์ JSP
ดังนั้นคุณต้องโทร<jsp:useBean>
ไปแนะนำ bean ในโปรเซสเซอร์ JSP เพื่อที่ว่าเมื่อโปรเซสเซอร์เห็น<jsp:getProperty>
มันจะรู้ว่ามันเกี่ยวข้องกับอะไร โดยพื้นฐานแล้ว<jsp:useBean>
ให้นิยามมันแล้ว<jsp:getProperty>
ใช้มัน หากคุณไม่ได้โทร<jsp:useBean>
ที่<jsp:getProperty>
จะพยายามที่จะใช้สิ่งที่ไม่ได้กำหนดหน่วยประมวลผล JSP จะบ่นและคุณได้รับกลับเป็นข้อยกเว้นของ:
jsp: getProperty สำหรับ bean ที่มีชื่อ 'person' ก่อนหน้านี้ไม่ได้มีการแนะนำชื่อตาม JSP.5.3
แต่ถ้าคุณอ่านรายละเอียดมันจะบอกว่า:
[... ] แนะนำให้ใช้คอนเทนเนอร์ (แต่ไม่จำเป็น) เพื่อเพิ่มข้อผิดพลาดในการแปล [... ]
ตัวอย่างเช่นหากคุณใช้ Tomcat มีorg.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY
คุณสมบัติของระบบที่ควบคุมข้อกำหนดในการให้อ็อบเจ็กต์ที่ใช้ใน<jsp:getProperty>
การ "แนะนำ" กับโปรเซสเซอร์ JSP ก่อนหน้านี้ (โดยทั่วไปบังคับใช้หรือไม่ใช่กฎ JSP.5.3) ดูตัวอย่างนี้Tomcat หน้าเอกสาร
ดังนั้นหากฉันเริ่มเซิร์ฟเวอร์ Tomcat ด้วยตัวแปรระบบเป็น:
-Dorg.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY=false
แล้วฉันสามารถใช้<jsp:getProperty>
โดยไม่ต้อง<jsp:useBean>
มีเงื่อนไขว่าผมแนะนำperson
BEAN อยู่ในขอบเขตบางวิธีอื่น ๆ (เช่นจากเซิร์ฟเล็ตด้วยrequest.setAttribute()
, session.setAttribute()
หรือapplication.setAttribute()
เพื่อให้<jsp:getProperty>
สามารถทำpageContext.findAttribute()
และมองหาถั่วที่มีชื่อperson
และพบว่า
หากคุณใช้คุณสมบัติของระบบนั้นเอาต์พุตที่สร้างโดย<jsp:getProperty>
แท็กจะเปลี่ยนไป มันไม่ขึ้นอยู่กับอีกต่อไป<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