web-dev-qa-db-ja.com

JSPページでスクリプトレットを使用しないようにする方法を教えてください。

私のJSPページでスクリプトレット(<%= ...%>)を使用することは、それほど良い考えではないと言われています。

もう少しJava/jspの経験がある人が、このコードをどのように「ベストプラクティス」にするためにこのコードを変更するかについて、いくつかの指針を教えてもらえますか?

このJSPは、実際には私のサイトメッシュのメインデコレータページです。基本的に私のWebデザインにはタブストリップとサブメニューがあり、現在のタブを強調表示して、現在のリクエストURIを見て正しいサブメニューを表示したいと思います。

<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>

<html>
<head>
  <title>My Events - <decorator:title /></title>
  <link href="<%= request.getContextPath() %>/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
  <a 
    <%= request.getRequestURI().contains("/events/") ? "class='selected'" : "" %>
    href='<%= request.getContextPath() %>/events/Listing.action'>Events</a>
  <a 
    <%= request.getRequestURI().contains("/people/") ? "class='selected'" : "" %>
    href='<%= request.getContextPath() %>/people/Listing.action'>People</a>
</div>

<div class="submenu">
  <% if(request.getRequestURI().contains("/events/")) { %>
    <a href="Listing.action">List of Events</a>
    |<a href="New.action">New Event</a>
  <% } %>
  <% if(request.getRequestURI().contains("/people/")) { %>
    <a href="Listing.action">List of People</a>
    |<a href="New.action">New Person</a>
  <% } %>  
  &nbsp;
</div>

<div class="body">
  <decorator:body />
</div>

</body>
</html>

皆さんありがとう

34
Chris

実際に完全にスクリプトレットなしで実行できることを自分の目で確認すると、さらに役立つと思います。

以下は、他の人たちの助けを借りて1対1で書き換えたものです [〜#〜] jstl [〜#〜] (単にドロップしてください jstl-1.2.jar in /WEB-INF/libcore および functions taglib:

<%@ taglib uri="http://Java.Sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://Java.Sun.com/jsp/jstl/functions" prefix="fn" %>

<html>
<head>
  <title>My Events - <decorator:title /></title>
  <link href="${pageContext.request.contextPath}/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
  <a 
    ${fn:contains(pageContext.request.requestURI, '/events/') ? 'class="selected"' : ''}
    href="${pageContext.request.contextPath}/events/Listing.action">Events</a>
  <a 
    ${fn:contains(pageContext.request.requestURI, '/people/') ? 'class="selected"' : ''}
    href="${pageContext.request.contextPath}/people/Listing.action">People</a>
</div>

<div class="submenu">
  <c:if test="${fn:contains(pageContext.request.requestURI, '/events/')}">
    <a href="Listing.action">List of Events</a>
    |<a href="New.action">New Event</a>
  </c:if>
  <c:if test="${fn:contains(pageContext.request.requestURI, '/people/')}">
    <a href="Listing.action">List of People</a>
    |<a href="New.action">New Person</a>
  </c:if>
  &nbsp;
</div>

これはより最適化された書き直しです。再利用するためにc:setを使用して式の結果を「キャッシュ」し、HTML <base>タグを使用してすべてのリンクにコンテキストパスを配置しないようにしています(すべての相対URLをそれに関連するあなたのウェブページ-先頭のスラッシュなし!):

<%@ taglib uri="http://Java.Sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://Java.Sun.com/jsp/jstl/functions" prefix="fn" %>

<c:set var="isEvents" value="${fn:contains(pageContext.request.requestURI, '/events/')}" />
<c:set var="isPeople" value="${fn:contains(pageContext.request.requestURI, '/people/')}" />

<html>
<head>
  <title>My Events - <decorator:title /></title>
  <base href="${pageContext.request.contextPath}">
  <link href="assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
  <a ${isEvents ? 'class="selected"' : ''} href="events/Listing.action">Events</a>
  <a ${isPeople ? 'class="selected"' : ''} href="people/Listing.action">People</a>
</div>

<div class="submenu">
  <c:if test="${isEvents}">
    <a href="Listing.action">List of Events</a>|<a href="New.action">New Event</a>
  </c:if>
  <c:if test="${isPeople}">
    <a href="Listing.action">List of People</a>|<a href="New.action">New Person</a>
  </c:if>
  &nbsp;
</div>

eventspeopleなどの「ハードコードされた」値をすべて収集し、アプリケーションスコープのMapにテキストをリンクして、各JSTLの下で使用すると、実際にさらに最適化できます。 <c:forEach>タブを表示します。

あなたのactual質問に関しては、スクリプトレットをdisable無効にすることができます(そしてそれを使用することに関するランタイムエラーを取得します) webappのweb.xmlに次のエントリを追加します。監視されているスクリプトレットを見つけるのに役立ちます。

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

ELの詳細については、 Java EEチュートリアルパートII、第5章 を確認してください。 ${pageContext}などの暗黙のELオブジェクトについて説明します here 。 JSTLの詳細については、 Java EEチュートリアルパートII、第7章 を確認してください。 JSTLとELは2つの別個のものであることに注意してください。 JSTLは標準のtaglibであり、ELはプログラムからバックエンドデータにアクセスできるようにするだけです。通常、JSTLのようなタグライブラリで使用されますが、テンプレートテキストでスタンドアロンで使用することもできます。

42
BalusC

余談ですが、<%= request.getContextPath() %>はそれほど眉をひそめられていないスクリプトレットの受け入れ可能な使用法ですか?

これはあまり人気のない意見かもしれませんが、単純な条件文とテキストの挿入だけであれば、スクリプトレットの使用に多くの欠点はありません。 (ifに注意してください)

私はおそらくJSTLと式言語を使用しますが、ほとんどの場合、入力が少ないため、IDEサポートが優れている可能性があります(ただし、優れたJSP IDE欠落している閉じ括弧なども見つけることができます)。

しかし、基本的には(「テンプレートからロジックを除外する」のように)、

<% if(request.getRequestURI().contains("/events/")) { %>

そして

${fn:contains(pageContext.request.requestURI, '/events/') 
9
Thilo

スクリプトレットは、世界で最悪のものではありません。重要な考慮事項は、誰がコードを保守するのかを考えることです。 Javaの経験があまりないWebデザイナーの場合は、タグライブラリを使用した方がよいでしょう。ただし、Java開発者がメンテナンスを行っている場合、スクリプトレットを使用する方が簡単な場合があります。

最終的にタグライブラリとJSTLを使用する場合、メンテナがタグライブラリについても学び、JSTLを知っていることを期待しています。一部の開発者は、これが自分の欲しいスキルまたはすでに持っているスキルであるため、問題ありませんが、JSPを数か月ごとに扱うだけでよい開発者にとっては、ニースで記述された明確に記述されたスクリプトレットで作業するほうがはるかに簡単です。 、使い慣れたJava。

6
Spike Williams

これはあなたの質問への直接の答えではありません(そして、いくつかの良いものはすでにあるので、私はそれに追加しようとはしません)、しかしあなたは言及しました:

もう少しJava/jspの経験がある人が、このコードをどのように変更するかについて、いくつかの指針を教えてくださいより「ベストプラクティス」、それが何であれ

私の意見では、JSPに関するベストプラクティスは、厳密にテンプレートエンジンとして使用し、それ以上(つまり、そこにビジネスロジックがない)にする必要があるということです。多くの人が指摘したように、JSTLを使用すると確実にその目的を達成できますが、JSTLを使用しても、JSPで多くのことを簡単に実行できます。

私は個人的には、JSPで開発する際にTerence Parrによって テンプレートエンジンでの厳密なモデル-ビューの分離 に記載されているルールに従うのが好きです。このペーパーでは、テンプレートエンジンの目的(モデルとビューを分離する)と、優れたテンプレートエンジンの特性について述べています。それはJSPをよく見て、それが良いテンプレートエンジンではない方法を指摘しています。当然のことながら、JSPは基本的に強力すぎるため、開発者は多くのことを実行できます。このペーパーを読むことを強くお勧めします。これは、JSPの「良い」部分に制限するのに役立ちます。

その論文の1つのセクションだけを読んだ場合は、第7章をお読みください。これには、次の規則が含まれています。

  1. ビューは、モデルデータオブジェクトを直接変更することによって、または副作用を引き起こすモデルのメソッドを呼び出すことによって、モデルを変更することはできません。つまり、テンプレートはモデルからデータにアクセスしてメソッドを呼び出すことができますが、そのような参照には副作用がない必要があります。データ参照は順序に依存しない必要があるため、このルールは部分的に発生します。セクション7.1を参照してください。
  2. ビューは依存データ値に基づいて計算を実行できません。計算は将来変更される可能性があり、どのような場合でもモデルに適切にカプセル化する必要があるためです。たとえば、ビューでは書籍の販売価格を「$ price * .90」として計算できません。モデルから独立するために、ビューはデータの意味について仮定を行うことができません。
  3. ビューは依存データ値を比較できませんが、複数値のデータ値の有無や長さなどのデータのプロパティをテストできます。 $ bloodPressure <120のようなテストは、医師が私たちの最高収縮期圧を下げ続けたいので、モデルに移動する必要があります。ビュー内の式は、$ bloodPressureOk!= nullなどのブール値をシミュレートする値の存在のテストで置き換える必要があります。テンプレートの出力は、モデルデータと計算に条件付きである可能性があります。条件付きはモデルで計算する必要があります。負の値を赤にする単純なテストでさえ、モデルで計算する必要があります。通常、適切なレベルの抽象化は、「部門xが損失を被っている」など、より高いレベルの抽象化です。
  4. ビューはデータ型の仮定を行うことができません。たとえば、ビューがデータ値を日付であると仮定する場合、いくつかの型の仮定は明白ですが、より微妙な型の仮定外観:テンプレートが$ userIDが整数であると想定している場合、プログラマーはテンプレートを壊さずにこの値をモデル内で非数値に変更できません。このルールは、colorCode [$ topic]や$ name [$ ID]などの配列のインデックス付けを禁止します。モデルが保証されない限り、想定される引数タイプがあるため(静的または動的)、ビューは引数を持つメソッドを呼び出すことができません。メソッドは単にそれらをオブジェクトとして扱いました。さらにグラフィックデザイナーはプログラマーではありません。それらがメソッドを呼び出して何を渡すかを知っていることを期待することは非現実的です。
  5. モデルのデータに表示またはレイアウト情報を含めることはできません。モデルは、データ値として偽装されたビューに表示情報を渡すことはできません。これには、他のデータ値に適用するテンプレートの名前を渡さないことが含まれます。

ちなみに、Terenceは、独自のテンプレートエンジン String Template を作成しました。これは、これらのルールを適用する上で非常に優れていると考えられています。個人的な経験はありませんが、次のプロジェクトで確認したいと思います。

6
Jack Leow

まず、タグライブラリを使用することをお勧めします。標準のタグライブラリ [〜#〜] jstl [〜#〜] を使用して、スクリプトレットが必要とする一般的なほとんどのことを実行できます。 struts2フレームワークやApacheのように使用される他の多くのより豊富なタグライブラリがあります。

例えば.

  <c:if test="${your condition}">
       Your Content
  </c:if>

あなたのifステートメントを置き換えるでしょう。

3

スクリプトレットの代替として推奨されるのは、JSTL式言語です。 ここ は良い概要です。次のようにtaglibを追加する必要があります。

<%@ taglib uri='http://Java.Sun.com/jsp/jstl/core' prefix='c' %>

例として、JSTLは、必要なものを提供する暗黙のオブジェクトの束を提供します。必要なのはpageContext.requestです。

したがって、<%request.getRequestURI%>${pageContext.request.requestURI}に置き換えることができます。

<c:if>タグを使用して条件を実行できます。

3
Jacob Mattison

いくつかのWebフレームワークを使用する必要があります。または、少なくともいくつかの便利なtaglib。または、FreeMarkerのようなテンプレートエンジン。

広告フレームワーク:

JSPによるコーディング方法が好きな場合は、Struts 2をお勧めします。

<s:if test="%{false}">
    <div>Will Not Be Executed</div>
</s:if>
<s:elseif test="%{true}">
    <div>Will Be Executed</div>
</s:elseif>
<s:else>
    <div>Will Not Be Executed</div>
</s:else>

次に、コンポーネント指向[〜#〜] jsf [〜#〜]があります。

OOPおよびJavaですべてをコーディングする場合は、Apache Wicketを試してください(私のお気に入り)またはGoogle Web Toolkit

2
Ondra Žižka