Warum kann ich <jsp: getProperty> nicht ohne <jsp: useBean> verwenden?

Jan 01 2021

Angenommen, es gibt ein Servlet mit Code:

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);
}

, das geht zum result.jspDrucken des Vornamens (Evan). Hier ist ein Bild davon, wie es aussehen würde (Quelle Head First Servlets und JSP):

Ich weiß, dass <jsp:useBean>dasselbe Personenobjekt durch Aufrufen zurückgegeben wird getAttribute()- da sie sich im selben Anforderungsbereich befinden . Während auf der anderen Seite, <jsp:getProperty>wird aufgerufen findAttribute(), buchstäblich zu versuchen, Attribut des Wertes "Person" zu finden .. und schließlich Evan zu drucken .

Aber was ist, wenn ich nicht verwendet habe <jsp:useBean>? Bedeutet das, dass ich auf Anforderung des Bereichs nicht auf das Attribut "Person" zugreifen konnte ? Ich meine , es würde noch da sein, auch wenn ich nicht verwenden , <jsp:useBean>.also warum ich gleiche haben muss Wert ( „Person“) innerhalb der beide ID in <jsp:useBean>und Namen innen <jsp:getProperty>? Einfaches Entfernen <jsp:useBean>bricht mein Programm.

Wenn Sie diese <jsp:getProperty>Aufrufe kennen findAttribute(), wäre es nicht logischer, wenn es ein einzelnes Attribut (wie den Attributnamen ) gäbe , das als Argument zum Suchen von Attributen in Bereichsseite > Anforderung> Sitzung> Anwendung verwendet wird ? Warum muss ich diese beiden Tags "binden": <jsp:useBean>und <jsp:getProperty>?

Antworten

2 LiveandLetLive Jan 01 2021 at 03:03

Was halten Sie von dem folgenden Code?

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

Sie müssen bereits richtig geraten haben, dass es nicht erfolgreich kompiliert werden kann .

Was ist nun mit dem folgenden Code?

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

Natürlich wird es erfolgreich kompiliert 1, da der Compiler jetzt versteht, was personist.

Ebenso mit

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

ohne zu erklären personals

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

wird nicht erfolgreich kompiliert .


1 Vorausgesetzt, es Person.classist da.

1 Bogdan Jan 01 2021 at 18:18

TL; DR: Sie sollten nur nicht vergessen , dass Sie verwenden müssen , <jsp:getProperty>mit , <jsp:useBean>weil die Spezifikation so sagt. <jsp:useBean>muss die Bean in den JSP-Prozessor einführen, bevor <jsp:getProperty>sie verwendet werden kann.

Die längere Erklärung:

Warum kann ich nicht <jsp:getProperty>ohne verwenden <jsp:useBean>?

Weil sie "etwas" entworfen wurden, um zusammenzuarbeiten. Ich weiß nicht, warum es so entschieden wurde (nur die Designer der JSP-Spezifikation können darauf antworten), aber die Spezifikation selbst hat Folgendes zu sagen <jsp:getProperty>:

Das mit dem Namen benannte Objekt muss entweder mit der Aktion jsp: useBean oder einer benutzerdefinierten Aktion mit einem zugeordneten VariablenInfo-Eintrag für diesen Namen in den JSP-Prozessor „eingeführt“ worden sein. Wenn das Objekt nicht auf diese Weise eingeführt wurde, wird die Containerimplementierung empfohlen (aber nicht erforderlich), um einen Übersetzungsfehler auszulösen, da die Seitenimplementierung gegen die Spezifikation verstößt.

Ich sage "etwas", das für die Zusammenarbeit entwickelt wurde, da Sie in einigen Fällen auch <jsp:getProperty>ohne verwenden können <jsp:useBean>, aber Sie müssen den JSP-Prozessor so konfigurieren, dass die JSP.5.3-Spezifikationsregel ignoriert wird (für Server, die dies zulassen).

Dies ist nicht sehr klar, also lassen Sie uns sehen, was mit einem Code passiert.

Ich habe die folgende JSP:

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

Ich habe diese Trennzeichen verwendet, damit ich sie später im von JSP generierten Servlet finden kann, wo sie zu folgendem Code führen:

  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");

Wenn Sie sich das ansehen <jsp:getProperty>, können Sie sehen, dass es eine Besetzung macht für test.Person:

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

Aber woher kam das? In Ihrem geben <jsp:getProperty>Sie einen Bean-Namen ( person) und einen Eigenschaftsnamen ( name) an, aber keine Klasse. Diese Attribute führen also nur zu findAttribute("person")und dann zu getName(). Woher kam die Klasse? Und die Antwort ist, der vorherige Aufruf, <jsp:useBean>dies im JSP-Prozessor einzuführen.

Sie müssen also aufrufen <jsp:useBean>, um die Bean in den JSP-Prozessor einzuführen, damit der Prozessor, wenn er sie sieht <jsp:getProperty>, weiß, womit er es zu tun hat. <jsp:useBean>Definiert es also im Grunde und <jsp:getProperty>verwendet es dann. Wenn Sie nicht anrufen <jsp:useBean>, <jsp:getProperty>wird der versuchen, etwas Undefiniertes zu verwenden, der JSP-Prozessor wird sich beschweren und Sie erhalten eine Ausnahme von:

jsp: getProperty für Bean mit dem Namen 'person'. Der Name wurde zuvor nicht gemäß JSP.5.3 eingeführt

Aber wenn Sie die Spezifikationen lesen, heißt es:

[...] Die Container-Implementierung wird empfohlen (aber nicht erforderlich), um einen [...] Übersetzungsfehler auszulösen.

Wenn Sie beispielsweise Tomcat verwenden, gibt es eine org.apache.jasper.compiler.Generator.STRICT_GET_PROPERTYSystemeigenschaft, die die Anforderung steuert, dass das verwendete Objekt <jsp:getProperty>zuvor in den JSP-Prozessor "eingeführt" werden muss (im Grunde genommen wird die JSP.5.3-Regel erzwungen oder nicht). Siehe zum Beispiel diese Tomcat-Dokumentationsseite .

Wenn ich meinen Tomcat-Server mit einer Systemvariablen von:

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

Dann kann ich <jsp:getProperty>ohne verwenden <jsp:useBean>, vorausgesetzt, dass ich die Bohne auf andere Weise in den Geltungsbereich einführe person(wie von einem Servlet mit request.setAttribute(), session.setAttribute()oder application.setAttribute()so, dass <jsp:getProperty>ich pageContext.findAttribute()eine Bohne mit dem Namen personsuchen und finden kann.

Wenn Sie diese Systemeigenschaft verwenden, <jsp:getProperty>ändert sich die vom Tag generierte Ausgabe . Es kommt nicht mehr darauf an <jsp:useBean>und der Gips wird entfernt:

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");

Wenn jemand daran interessiert ist, wie sich all dieses Durcheinander entwickelt, sollten folgende Klassen (für einen Tomcat-Server) betrachtet werden: org.apache.jasper.compiler.Validatorund org.apache.jasper.compiler.Generator.