<jsp:useBean>なしで<jsp:getProperty>を使用できないのはなぜですか?

Jan 01 2021

コードを持つサーブレットがあるとします。

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名を印刷するために行きます(エヴァン)。これがどのように見えるかの写真です(ソースHead FirstサーブレットとJSP):

同じリクエストスコープ内にあるため、-<jsp:useBean>を呼び出すことで同じPersonオブジェクトが返されることを私は知っています。反対側にいる間、文字通り値「人」の属性を見つけようとするために呼び出します..そして最終的にエヴァンを印刷します。getAttribute()<jsp:getProperty>findAttribute()

しかし、使用しなかった場合は<jsp:useBean>どうなりますか?スコープリクエストで「person」属性にアクセスできなかったということですか?私はそれはまだ私が使用しなかった場合でも、存在することになるわけ<jsp:useBean>.私は同じ持っている必要がありますだから、なぜの両方の内側(「人物」)のID<jsp:useBean>し、名前の内側<jsp:getProperty>?単純な削除<jsp:useBean>は私のプログラムを壊します。

その<jsp:getProperty>呼び出しを知っているとfindAttribute()、スコープページ>リクエスト>セッション>アプリケーションで属性を見つけるための引数として使用される単一の属性(属性名など)があった場合、より論理的ではないでしょうか?なぜこれらの2つのタグを「結び付ける」必要があるのですか:と?<jsp:useBean><jsp:getProperty>

回答

2 LiveandLetLive Jan 01 2021 at 03:03

次のコードについてどう思いますか?

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

もちろん、コンパイラが何であるかを理解するようになったため、正常にコンパイルされます1person

同様に、

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

personとして宣言せずに

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

正常にコンパイルされません


1Person.classそこにあると仮定します。

1 Bogdan Jan 01 2021 at 18:18

TL; DR:あなたはちょうどあなたが使用する必要があることを覚えておいてください<jsp:getProperty><jsp:useBean>仕様がそう言うので。<jsp:useBean>Beanを<jsp:getProperty>使用する前に、JSPプロセッサにBeanを導入する必要があります。

より長い説明:

なぜ私が使用することはできません<jsp:getProperty>なし<jsp:useBean>

それらは「ある程度」一緒に機能するように設計されていたからです。なぜそのように決定されたのかはわかりませんが(JSP仕様の設計者だけがそれに答えることができます)、仕様自体には次のように書かれてい<jsp:getProperty>ます。

名前で指定されたオブジェクトは、jsp:useBeanアクションまたはこの名前に関連付けられたVariableInfoエントリを持つカスタムアクションのいずれかを使用して、JSPプロセッサに「導入」されている必要があります。オブジェクトがこの方法で導入されなかった場合、ページの実装は仕様に違反しているため、変換エラーを発生させるためにコンテナの実装が推奨されます(必須ではありません)。

一緒に動作するように設計された「やや」と言います。これは、<jsp:getProperty>なし<jsp:useBean>で使用できる場合もありますが、JSP.5.3仕様ルールを無視するようにJSPプロセッサを構成する必要があるためです(これを許可するサーバーの場合)。

これはあまり明確ではないので、いくつかのコードで何が起こるか見てみましょう。

私は次のJSPを持っています:

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

これらの区切り文字を使用して、後で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>、JSPプロセッサにBeanを導入するために呼び出す必要があります。これにより、プロセッサは、処理している<jsp:getProperty>ものを認識したときにそれを認識できます。つまり、基本的に<jsp:useBean>は、それ<jsp:getProperty>を定義してから使用します。を呼び出さないと<jsp:useBean>、は<jsp:getProperty>未定義のものを使用しようとし、JSPプロセッサは文句を言い、次の例外が返されます。

'person'という名前のBeanのjsp:getProperty。名前は、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>Iご紹介という条件で、personBean内のSCOPEに(とサーブレットからのような他の方法request.setAttribute()session.setAttribute()またはapplication.setAttribute()それがそう<jsp:getProperty>行うことができますpageContext.findAttribute()という名前のBeanのと見て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.Validatororg.apache.jasper.compiler.Generator