Tại sao tôi không thể sử dụng <jsp: getProperty> mà không có <jsp: useBean>?
Giả sử có servlet có mã:
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);
}
, sẽ được result.jsp
in ra tên đã cho (Evan). Đây là hình ảnh của nó trông như thế nào (nguồn Head First Servlets và JSP):
![](https://post.nghiatu.com/assets/images/s/vOtR0.png)
Tôi biết rằng <jsp:useBean>
trả về cùng một đối tượng Person bằng cách gọi getAttribute()
- vì chúng ở trong cùng một phạm vi yêu cầu . Trong khi ở phía bên kia, <jsp:getProperty>
sẽ gọi findAttribute()
theo nghĩa đen là cố gắng tìm thuộc tính của giá trị "người" .. và cuối cùng in Evan .
Nhưng nếu tôi không sử dụng <jsp:useBean>
thì sao? Điều đó có nghĩa là tôi không thể truy cập thuộc tính "person" theo yêu cầu phạm vi ? Ý tôi là nó sẽ vẫn ở đó, ngay cả khi tôi không sử dụng <jsp:useBean>.
Vậy tại sao tôi phải có cùng giá trị ("người") bên trong cả id in <jsp:useBean>
và name bên trong <jsp:getProperty>
? Loại bỏ đơn giản <jsp:useBean>
phá vỡ chương trình của tôi.
Biết rằng <jsp:getProperty>
các lệnh gọi findAttribute()
, sẽ hợp lý hơn nếu có một thuộc tính duy nhất (như tên-thuộc tính ), sẽ được sử dụng làm đối số để tìm các thuộc tính trong trang phạm vi > yêu cầu> phiên> ứng dụng ? Tại sao tôi phải "buộc" hai thẻ đó: <jsp:useBean>
và <jsp:getProperty>
?
Trả lời
Bạn nghĩ gì về đoạn mã sau đây?
public class Main {
public static void main(String[] args) {
System.out.println(person);
}
}
Bạn hẳn đã đoán đúng rằng nó sẽ không được biên dịch thành công .
Bây giờ, những gì về đoạn mã sau đây?
public class Main {
public static void main(String[] args) {
Person person = new Person();// Declaring person
System.out.println(person);
}
}
Tất nhiên, nó sẽ được biên dịch thành công 1 vì bây giờ trình biên dịch hiểu những gì person
là.
Tương tự, sử dụng
<jsp:getProperty name="person" property="name">
mà không cần khai báo person
là
<!-- Declaring person -->
<jsp:useBean id="person" class="foo.Person" scope="request" />
sẽ không được biên dịch thành công .
1 Giả sử Person.class
là có.
TL; DR: Bạn chỉ nên nhớ rằng bạn cần sử dụng <jsp:getProperty>
với <jsp:useBean>
vì đặc điểm kỹ thuật nói như vậy. <jsp:useBean>
cần giới thiệu bean với bộ xử lý JSP, trước khi <jsp:getProperty>
có thể sử dụng nó.
Lời giải thích dài hơn:
Tại sao tôi không thể sử dụng
<jsp:getProperty>
mà không có<jsp:useBean>
?
Bởi vì chúng được thiết kế "phần nào" để hoạt động cùng nhau. Tôi không biết tại sao nó lại được quyết định như vậy (chỉ các nhà thiết kế của đặc điểm kỹ thuật JSP mới có thể trả lời điều đó), nhưng bản thân thông số kỹ thuật có điều này để nói về <jsp:getProperty>
:
Đối tượng được đặt tên phải được “giới thiệu” với bộ xử lý JSP bằng cách sử dụng hành động jsp: useBean hoặc một hành động tùy chỉnh với mục nhập VariableInfo được liên kết cho tên này. Nếu đối tượng không được giới thiệu theo cách này, thì việc triển khai vùng chứa được khuyến nghị (nhưng không bắt buộc) sẽ gây ra lỗi dịch, vì việc triển khai trang vi phạm đặc điểm kỹ thuật.
Tôi nói "phần nào" được thiết kế để hoạt động cùng nhau, bởi vì trong một số trường hợp bạn có thể sử dụng <jsp:getProperty>
mà không cần <jsp:useBean>
, nhưng bạn phải định cấu hình bộ xử lý JSP để bỏ qua quy tắc đặc tả JSP.5.3 (đối với các máy chủ cho phép điều đó).
Điều này không rõ ràng lắm, vì vậy hãy xem điều gì xảy ra với một số đoạn mã.
Tôi có JSP sau:
-------------------------------------------------------------------
<jsp:useBean id="person" class="test.Person" scope="application" />
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<jsp:getProperty name="person" property="name" />
-------------------------------------------------------------------
Tôi đã sử dụng các dấu phân tách đó để sau này có thể tìm thấy chúng trong servlet được tạo JSP, nơi chúng dẫn đến mã này:
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");
Nếu bạn nhìn vào, <jsp:getProperty>
bạn có thể thấy rằng nó diễn thành test.Person
:
org.apache.jasper.runtime.JspRuntimeLibrary.toString((((test.Person)_jspx_page_context.findAttribute("person")).getName()))
Nhưng điều đó đến từ đâu? Trong của <jsp:getProperty>
bạn, bạn chỉ định một tên bean ( person
) và một tên thuộc tính ( name
), nhưng không có lớp. Vì vậy, những thuộc tính chỉ dẫn đến findAttribute("person")
và sau đó là kết quả getName()
. Lớp học được lấy từ đâu? Và câu trả lời là, cuộc gọi trước đó đã <jsp:useBean>
giới thiệu điều này trong bộ xử lý JSP.
Vì vậy, bạn phải gọi <jsp:useBean>
để giới thiệu bean trong bộ xử lý JSP để khi bộ xử lý nhìn thấy <jsp:getProperty>
nó, nó sẽ biết nó đang xử lý những gì. Vì vậy, về cơ bản, hãy <jsp:useBean>
xác định nó, sau đó <jsp:getProperty>
sử dụng nó. Nếu bạn không gọi <jsp:useBean>
, <jsp:getProperty>
nó sẽ cố gắng sử dụng thứ gì đó không xác định, bộ xử lý JSP sẽ phàn nàn và bạn nhận lại một ngoại lệ:
jsp: getProperty cho bean có tên 'person'. Tên không được giới thiệu trước đây theo JSP.5.3
Nhưng nếu bạn đọc các thông số kỹ thuật, nó cho biết:
[...] việc triển khai vùng chứa được khuyến nghị (nhưng không bắt buộc) để phát sinh lỗi dịch [...]
Ví dụ: nếu bạn sử dụng Tomcat, có một thuộc tính org.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY
hệ thống kiểm soát yêu cầu để đối tượng được sử dụng <jsp:getProperty>
trước đó được "giới thiệu" với bộ xử lý JSP (về cơ bản, thực thi hoặc không thực thi quy tắc JSP.5.3). Ví dụ xem trang tài liệu Tomcat này .
Vì vậy, nếu tôi khởi động máy chủ Tomcat của mình với một biến hệ thống là:
-Dorg.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY=false
Sau đó, tôi có thể sử dụng <jsp:getProperty>
mà không cần <jsp:useBean>
, CUNG CẤP RẰNG TÔI GIỚI THIỆU person
BEAN TRONG PHẠM VI MỘT SỐ CÁCH KHÁC (chẳng hạn như từ một servlet với request.setAttribute()
, session.setAttribute()
hoặc application.setAttribute()
như vậy <jsp:getProperty>
có thể thực hiện pageContext.findAttribute()
và tìm một bean có tên person
và tìm nó.
Nếu bạn sử dụng thuộc tính hệ thống đó, thì kết quả đầu ra do <jsp:getProperty>
thẻ tạo ra sẽ thay đổi. Nó không còn phụ thuộc vào <jsp:useBean>
và dàn diễn viên bị loại bỏ:
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");
Nếu ai đó quan tâm đến cách tất cả mớ hỗn độn này diễn ra, các lớp cần xem xét (đối với máy chủ Tomcat) là: org.apache.jasper.compiler.Validator
và org.apache.jasper.compiler.Generator
.