1. ホーム

[解決済み】JSP 2を使用して、JSPファイル内のJavaコードを回避するにはどうすればよいですか?

2022-03-18 19:54:47

質問

私はJavaEEの初心者ですが、次の3行のようなものがあることは知っています。

<%= x+1 %>
<%= request.getParameter("name") %>
<%! counter++; %>

は古いコーディング方法であり、JSPバージョン2ではJSPファイル内のJavaコードを回避する方法が存在します。代替となるJSP 2の行、そしてこの手法は何と呼ばれているのでしょうか?

どのように解決するのですか?

の使用は スクリプトレット (これらの <% %> のもの)を JSP が誕生してからは、確かに非常に敬遠されるようになりました。 タグライブズ (例えば JSTL ) と EL ( 表現言語 , それらの ${} のようなもの)を2001年までさかのぼりました。

の主なデメリットは、以下の通りです。 スクリプト があります。

  1. 再利用性。 スクリプトレットを再利用できない。
  2. 置き換え可能であること。 スクリプトレットを抽象化することはできません。
  3. OO-ability。 継承・合成を生かせない。
  4. デバッガビリティ。 スクリプトレットが中途半端に例外を投げると、空白のページしか表示されません。
  5. テスト容易性。 スクリプトはユニットテスト可能ではありません。
  6. メンテナンス性。 コードロジックが混在/乱雑/重複しているため、メンテナンスに時間がかかる。

<ストライク 日 また、オラクル自身も JSPコーディング規約 を使用しないようにすることです。 スクリプトレット 同じ機能が(タグ)クラスで可能であれば、いつでも。以下は、関連するいくつかの引用です。

<ブロッククオート

JSP 1.2仕様より、ウェブアプリケーションでは、JSP Standard Tag Library (JSTL) を使用することが強く推奨されており、以下のようになります。 JSPスクリプトレットの必要性を減らす を使用します。JSTL を使用したページは、一般に、読みやすく、保守しやすくなります。

...

可能な限り JSPスクリプトレットを避ける タグライブラリが同等の機能を提供している場合 これは、ページを読みやすくし、メンテナンスしやすくし、ビジネスロジックとプレゼンテーションロジックを分離するのに役立ち、ページをJSP 2.0スタイルのページに進化させやすくします(JSP 2.0 仕様はスクリプトレットの使用をサポートしていますが、強調はしていません)。

...

モデル・ビュー・コントローラー(MVC)デザインパターンを採用し、プレゼンテーション層とビジネスロジックの間の結合を減らすという精神で。 JSPスクリプトレットは使用しないでください。 は、ビジネスロジックを記述するために使用します。むしろ、JSPスクリプトレットは、クライアントのリクエストを処理して戻ってきたデータ(quot;値オブジェクト"とも呼ばれる)を、適切なクライアント対応フォーマットに変換するために必要な場合に使用されます。その場合でも、フロントコントローラサーブレットやカスタムタグを使用した方がよいでしょう。


を置き換える方法 スクリプトレット は、完全にそのコード/ロジックの唯一の目的に依存します。多くの場合、このコードは完全なJavaクラスの中に置かれることになります。

  • を呼び出したい場合 同じ でのJavaコード あらゆる リクエストされたページに関係なく、少なくても多くても、 例えば、ユーザがログインしているかどうかをチェックするために フィルタ で、それに応じたコードを記述します。 doFilter() メソッドを使用します。例

      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
          if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
              ((HttpServletResponse) response).sendRedirect("login"); // Not logged in, redirect to login page.
          } else {
              chain.doFilter(request, response); // Logged in, just continue request.
          }
      }
    
    

    にマッピングされた場合、適切な <url-pattern> をカバーすれば、JSPページ全体に同じコードの断片をコピーペーストする必要はありません。


  • もし、あるJavaコードを呼び出して GET リクエストを処理する 例えば、クエリパラメータに基づいてデータベースからリストをプリロードし、必要に応じてテーブルに表示させることができます。 サーブレット で、それに応じたコードを doGet() メソッドを使用します。例

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          try {
              List<Product> products = productService.list(); // Obtain all products.
              request.setAttribute("products", products); // Store products in request scope.
              request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response); // Forward to JSP page to display them in a HTML table.
          } catch (SQLException e) {
              throw new ServletException("Retrieving products failed!", e);
          }
      }
    
    

    こうすることで、例外処理も容易になります。DBへのアクセスはJSPのレンダリング中ではなく、JSPが表示される遥か前に行われます。DBアクセスが例外を投げるたびにレスポンスを変更する可能性があります。上記の例では、デフォルトのエラー500ページが表示されます。 <error-page>web.xml .


  • もし、あるJavaコードを呼び出して POST リクエストを処理する 例えば、送信された HTML フォームからデータを収集し、それを使って何らかのビジネス上の処理 (変換、検証、DB への保存など) を行う場合、以下のように サーブレット を作成し、それに応じたコードを doPost() メソッドを使用します。例

      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          String username = request.getParameter("username");
          String password = request.getParameter("password");
          User user = userService.find(username, password);
    
          if (user != null) {
              request.getSession().setAttribute("user", user); // Login user.
              response.sendRedirect("home"); // Redirect to home page.
          } else {
              request.setAttribute("message", "Unknown username/password. Please retry."); // Store error message in request scope.
              request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to JSP page to redisplay login form with error.
          }
      }
    
    

    この方法によって、異なる結果ページへの対処が簡単になります。エラーの場合はバリデーションエラーとともにフォームを再表示します (この例では ${message} EL )、成功した場合は目的のページに移動するだけです。


  • もし、あるJavaコードを呼び出して 制御 を実装することで、リクエストとレスポンスの実行計画や宛先を変更することができます。 サーブレット に従って MVCのフロントコントローラーパターン . 例.

      protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          try {
              Action action = ActionFactory.getAction(request);
              String view = action.execute(request, response);
    
              if (view.equals(request.getPathInfo().substring(1)) {
                  request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
              } else {
                  response.sendRedirect(view);
              }
          } catch (Exception e) {
              throw new ServletException("Executing action failed.", e);
          }
      }
    
    

    または、以下のようなMVCフレームワークを採用するだけです。 JSF , スプリングMVC , ウィケット などを使用することで、カスタムサーブレットを使用せずに、JSP/FaceletsページとJavaBeanクラスだけで終わらせることができます。


  • もし、あるJavaコードを呼び出して フローを制御する のような(既存の)フローコントロールタグライブを取得する必要があります。 JSTLコア . 例) List<Product> をテーブルの中に入れてください。

      <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
      ...
      <table>
          <c:forEach items="${products}" var="product">
              <tr>
                  <td>${product.name}</td>
                  <td>${product.description}</td>
                  <td>${product.price}</td>
              </tr>
          </c:forEach>
      </table>
    
    

    HTML の中に XML スタイルのタグをうまく組み込むことで、さまざまな開閉中括弧を使ったスクリプトレットの束よりも読みやすい (つまり保守しやすい) コードになります ( この閉じ中括弧はいったいどこのものなのでしょうか。 ). 簡単な方法は、Webアプリケーションで、次のような場合に例外を発生させるように設定することです。 スクリプト に以下の部分を追加することで、まだ使用されています。 web.xml :

      <jsp-config>
          <jsp-property-group>
              <url-pattern>*.jsp</url-pattern>
              <scripting-invalid>true</scripting-invalid>
          </jsp-property-group>
      </jsp-config>
    
    

    フェイスレット JSPの後継であり、Java EEが提供するMVCフレームワークの一部である JSF は、すでに ではない を使用することができます。 スクリプトレット . こうすることで、自動的に正しい方法で物事を行うことを強制されます。


  • もし、あるJavaコードを呼び出して にアクセスし、表示します。 バックエンドのデータは、JSPページ内でEL(Expression Language)を使用する必要があります。 ${} のようなものです。例:投稿された入力値を再表示する。

      <input type="text" name="foo" value="${param.foo}" />
    
    

    ${param.foo} の結果を表示します。 request.getParameter("foo") .


  • を呼び出したい場合 ユーティリティ JSPページで直接Javaコード(通常は public static メソッド)を定義する場合、それらをEL関数として定義する必要があります。標準的な 関数タグリブ はJSTLにありますが また、自分で簡単に関数を作成することもできます。 . 以下は、JSTLの例です。 fn:escapeXml を防ぐのに有効です。 XSS 攻撃 .

      <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
      ...
      <input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
    
    

    XSS の感度は、Java/JSP/JSTL/EL/その他に特別な関係があるわけではなく、この問題は、次のように考慮する必要があることに注意してください。 あらゆる ウェブアプリケーションを開発する際に の問題は スクリプトレット は、少なくとも標準的なJava APIを使用して、組み込みの予防手段を提供しないことです。JSPの後継であるFaceletsは、すでに暗黙のHTMLエスケープを備えているので、FaceletsのXSSホールを心配する必要はありません。

こちらもご覧ください。