Mengapa saya tidak dapat menggunakan <jsp: getProperty> tanpa <jsp: useBean>?
Katakanlah ada servlet yang memiliki kode:
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);
}
, Itu result.jsp
untuk mencetak nama yang diberikan (Evan). Berikut adalah gambar tampilannya (sumber Head First Servlets dan JSP):
Saya tahu bahwa <jsp:useBean>
mengembalikan objek Person yang sama dengan memanggil getAttribute()
- karena mereka berada dalam cakupan permintaan yang sama . Sementara di sisi lain, <jsp:getProperty>
akan terpanggil findAttribute()
untuk secara harfiah mencoba menemukan atribut nilai "person" .. dan akhirnya mencetak Evan .
Tetapi bagaimana jika saya tidak menggunakan <jsp:useBean>
? Apakah itu berarti saya tidak dapat mengakses atribut "person" pada permintaan cakupan ? Maksud saya itu akan tetap ada, bahkan jika saya tidak menggunakan <jsp:useBean>.
Jadi mengapa saya harus memiliki nilai yang sama ("person") di dalam id in <jsp:useBean>
dan name inside <jsp:getProperty>
? Penghapusan sederhana <jsp:useBean>
merusak program saya.
Mengetahui <jsp:getProperty>
panggilan tersebut findAttribute()
, bukankah akan lebih logis jika ada satu atribut (seperti nama-atribut ), yang akan digunakan sebagai argumen untuk menemukan atribut di halaman cakupan > permintaan> sesi> aplikasi ? Mengapa saya harus "mengikat" kedua tanda tersebut: <jsp:useBean>
dan <jsp:getProperty>
?
Jawaban
Apa pendapat Anda tentang kode berikut?
public class Main {
public static void main(String[] args) {
System.out.println(person);
}
}
Anda pasti sudah menebak dengan benar bahwa itu tidak akan berhasil dikompilasi .
Sekarang, bagaimana dengan kode berikut?
public class Main {
public static void main(String[] args) {
Person person = new Person();// Declaring person
System.out.println(person);
}
}
Tentu saja, ini akan berhasil dikompilasi 1 karena sekarang kompilator mengerti apa person
itu.
Demikian pula dengan menggunakan
<jsp:getProperty name="person" property="name">
tanpa menyatakan person
sebagai
<!-- Declaring person -->
<jsp:useBean id="person" class="foo.Person" scope="request" />
tidak akan berhasil dikompilasi .
1 Dengan asumsi Person.class
ada.
TL; DR: Anda harus ingat bahwa Anda perlu menggunakan <jsp:getProperty>
dengan <jsp:useBean>
karena spesifikasinya mengatakan demikian. <jsp:useBean>
perlu memperkenalkan bean ke prosesor JSP, sebelum <jsp:getProperty>
dapat menggunakannya.
Penjelasan yang lebih panjang:
Mengapa saya tidak dapat menggunakan
<jsp:getProperty>
tanpa<jsp:useBean>
?
Karena mereka "agak" dirancang untuk bekerja sama. Saya tidak tahu mengapa diputuskan seperti itu (hanya perancang spesifikasi JSP yang dapat menjawabnya), tetapi spesifikasi itu sendiri mengatakan ini tentang <jsp:getProperty>
:
Objek yang dinamai dengan nama tersebut harus telah "diperkenalkan" ke prosesor JSP menggunakan tindakan jsp: useBean atau tindakan kustom dengan entri VariableInfo terkait untuk nama ini. Jika objek tidak diperkenalkan dengan cara ini, penerapan penampung disarankan (tetapi tidak wajib) untuk menimbulkan kesalahan terjemahan, karena penerapan laman melanggar spesifikasi.
Saya mengatakan "agak" dirancang untuk bekerja sama, karena dalam beberapa kasus Anda dapat menggunakan <jsp:getProperty>
tanpa <jsp:useBean>
, tetapi Anda harus mengkonfigurasi prosesor JSP untuk mengabaikan aturan spesifikasi JSP.5.3 (untuk server yang mengizinkannya).
Ini tidak terlalu jelas, jadi mari kita lihat apa yang terjadi dengan beberapa kode.
Saya memiliki JSP berikut:
-------------------------------------------------------------------
<jsp:useBean id="person" class="test.Person" scope="application" />
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<jsp:getProperty name="person" property="name" />
-------------------------------------------------------------------
Saya menggunakan pembatas itu sehingga saya nanti dapat menemukannya di servlet yang dihasilkan JSP, di mana mereka menghasilkan kode ini:
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");
Jika Anda melihatnya, <jsp:getProperty>
Anda dapat melihat bahwa itu melakukan cast ke test.Person
:
org.apache.jasper.runtime.JspRuntimeLibrary.toString((((test.Person)_jspx_page_context.findAttribute("person")).getName()))
Tapi dari mana asalnya? Dalam Anda, <jsp:getProperty>
Anda menentukan nama kacang ( person
) dan nama properti ( name
), tetapi tidak ada kelas. Jadi atribut itu hanya menghasilkan findAttribute("person")
lalu masuk getName()
. Dari mana kelas itu diambil? Dan jawabannya adalah, panggilan sebelumnya untuk <jsp:useBean>
memperkenalkan prosesor JSP ini.
Jadi, Anda harus memanggil <jsp:useBean>
untuk memperkenalkan kacang di prosesor JSP sehingga saat prosesor melihatnya, <jsp:getProperty>
ia tahu apa yang dihadapinya. Jadi pada dasarnya, <jsp:useBean>
tentukan, lalu <jsp:getProperty>
gunakan. Jika Anda tidak menelepon <jsp:useBean>
, <jsp:getProperty>
akan mencoba menggunakan sesuatu yang tidak ditentukan, prosesor JSP akan mengeluh, dan Anda mendapatkan kembali pengecualian:
jsp: getProperty untuk bean dengan nama 'person'. Nama tidak diperkenalkan sebelumnya sesuai JSP.5.3
Tetapi jika Anda membaca spesifikasinya, dikatakan:
[...] implementasi penampung disarankan (tetapi tidak wajib) untuk menimbulkan kesalahan terjemahan [...]
Jika Anda menggunakan Tomcat, misalnya, ada org.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY
properti sistem yang mengontrol persyaratan agar objek yang digunakan <jsp:getProperty>
sebelumnya "diperkenalkan" ke prosesor JSP (pada dasarnya, menerapkan atau tidak aturan JSP.5.3). Lihat misalnya halaman dokumentasi Tomcat ini .
Jadi, jika saya memulai server Tomcat saya dengan variabel sistem:
-Dorg.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY=false
Kemudian saya dapat menggunakan <jsp:getProperty>
tanpa <jsp:useBean>
, TERBUKTI BAHWA SAYA MEMPERKENALKAN person
KACANG DALAM LINGKUP DENGAN BEBERAPA CARA LAIN (seperti dari servlet dengan request.setAttribute()
, session.setAttribute()
atau application.setAttribute()
lebih yang <jsp:getProperty>
dapat melakukan pageContext.findAttribute()
dan mencari kacang bernama person
dan menemukannya.
Jika Anda menggunakan properti sistem itu, keluaran yang dihasilkan oleh <jsp:getProperty>
tag berubah. Itu tidak lagi tergantung <jsp:useBean>
dan gips dilepas:
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");
Jika seseorang tertarik dengan bagaimana semua kekacauan ini terungkap, kelas yang harus dilihat (untuk server Tomcat) adalah: org.apache.jasper.compiler.Validator
dan org.apache.jasper.compiler.Generator
.