web-dev-qa-db-ja.com

JSP /サーブレットの隠された機能

私は、JSP /サーブレットを作成するときに使用されるあなたのトリックなどに興味があります。始めます:

少し最近、あるJSPタグの出力を別のタグの属性に含める方法を見つけました。

<c:forEach items="${items}">
  <jsp:attribute name="var">
    <mytag:doesSomething/>
  </jsp:attribute>
  <jsp:body>
    <%-- when using jsp:attribute the body must be in this tag --%>
  </jsp:body>
</c:forEach>
76
mkoryak

注:JSP /サーブレットの「隠された機能」について考えるのは難しいと思います。私の意見では、「ベストプラクティス」の方がより適切な表現であり、私はそれらのどれでも考えることができます。また、JSP /サーブレットの経験にもよります。長年の開発の後、「隠された機能」はもう見えません。とにかく、多くの初心者がそれを完全には認識していないことが数年でわかった小さな「ベストプラクティス」のいくつかを挙げます。多くの初心者の目には、これらは「隠された機能」として分類されます。とにかく、ここにリストがあります:)


直接アクセスからJSPページを隠す

_/WEB-INF_フォルダーにJSPファイルを配置することで、たとえば_http://example.com/contextname/WEB-INF/page.jsp_によって、直接アクセスからそれらを効果的に非表示にします。これは_404_になります。その後、サーブレットで RequestDispatcher または _jsp:include_ を使用することによってのみそれらにアクセスできます。


JSPの前処理リクエスト

ほとんどはサーブレットの doPost() topost-処理(フォーム送信)について知っていますが、ほとんどの場合、サーブレットの doGet() メソッドを使用してpre-リクエストを処理できることを知りませんJSP。例えば:

_protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    List<Item> items = itemDAO.list();
    request.setAttribute("items", items);
    request.getRequestDispatcher("/WEB-INF/page.jsp").forward(request, response);
}
_

これは、JSTLの_c:forEach_を使用して表示される表形式のデータをプリロードするために使用されます。

_<table>
    <c:forEach items="${items}" var="item">
        <tr><td>${item.id}</td><td>${item.name}</td></tr>
    </c:forEach>
</table>
_

そのようなサーブレットを_url-pattern_(または_/page_)の_/page/*_にマッピングし、ブラウザのアドレスバーまたはプレーンなバニラリンクで_http://example.com/contextname/page_を呼び出すだけで実行できます。も参照してください。 サーブレットでのdoGetおよびdoPost


動的インクルード

ELは _jsp:include_ で使用できます。

_<jsp:include page="/WEB-INF/${bean.page}.jsp" />
_

bean.getPage()は、有効なページ名を返すことができます。


ELはどのゲッターにもアクセスできます

EL自体は、アクセスされるオブジェクトがフル価値のあるJavabeanである必要はありません。 ELでアクセスするには、getまたはisが前に付いている引数なしのメソッドの存在で十分です。例えば。:

_${bean['class'].name}
_

これは bean.getClass().getName() の値を返します。ここで、getClass()メソッドは実際には Object#getClass() から継承されます。ここで言及されている理由により、classは「ブレース表記」_[]_を使用して指定されていることに注意してください EL式言語でのインスタンスのチェック

_${pageContext.session.id}
_

これは pageContext.getSession().getId() の値を返します。これはa.oで便利です。 アプレットはサーブレットのインスタンスと通信できますか

_${pageContext.request.contextPath}
_

これは pageContext.getRequest().getContextPath() の値を返します。これはa.oで便利です。 コンテキストルート名を含めずに相対パスを使用する方法


ELはマップにもアクセスできます

次のEL表記

_${bean.map.foo}
_

bean.getMap().get("foo")に解決されます。 Mapキーにドットが含まれている場合は、引用符付きのキーで「中かっこ表記」_[]_を使用できます。

_${bean.map['foo.bar']}
_

これはbean.getMap().get("foo.bar")に解決されます。動的キーが必要な場合は、中かっこ表記も使用しますが、引用符は付けません。

_${bean.map[otherbean.key]}
_

これはbean.getMap().get(otherbean.getKey())に解決されます。


JSTLでマップを反復する

_c:forEach_ を使用してMapを反復することもできます。反復ごとに _Map.Entry_ が与えられ、これにはgetKey()およびgetValue()メソッドがあります(これにより、ELで_${entry.key}_および_${entry.value}_)。例:

_<c:forEach items="${bean.map}" var="entry">
    Key: ${entry.key}, Value: ${entry.value} <br>
</c:forEach>
_

も参照してください。 jstlによるデバッグ-正確には?


JSPで現在の日付を取得する

_jsp:useBean_ を使用して現在の日付を取得し、JSTLを使用してフォーマットすることができます _fmt:formatDate_

_<jsp:useBean id="date" class="Java.util.Date" />
...
<p>Copyright &copy; <fmt:formatDate value="${date}" pattern="yyyy" /></p>
_

これは(現時点では)次のように印刷されます: "Copyright©2010"。


使いやすいURL

わかりやすいURLを作成する簡単な方法は、 HttpServletRequest#getPathInfo() を使用して、JSPを_/WEB-INF_に非表示にすることです。

_protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.getRequestDispatcher("/WEB-INF" + request.getPathInfo() + ".jsp").forward(request, response);
}
_

たとえば、このサーブレットを_/pages/*_にマップすると、_http://example.com/contextname/pages/foo/bar_へのリクエストは_/WEB-INF/foo/bar.jsp_を効果的に表示します。 _/_でpathinfoを分割することでさらに一歩進んで、最初の部分のみをJSPページURLとして、残りを「ビジネスアクション」として取得できます(サーブレットをページコントローラとして機能させます) )。も参照してください。 デザインパターンWebベースのアプリケーション


_${param}_を使用してユーザー入力を再表示する

HttpServletRequest#getParameterMap() を参照する暗黙のELオブジェクト_${param}_は、JSPでのフォーム送信後にユーザー入力を再表示するために使用できます。

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

これは基本的にrequest.getParameterMap().get("foo")と同じです。も参照してください。 サーブレットにフォームを送信した後、HTMLフォームのフィールド値をJSPに保持するにはどうすればよいですか?
XSSを防ぐことを忘れないでください!次の章を参照してください。


XSSを防ぐJSTL

サイトが [〜#〜] xss [〜#〜] にならないようにするには、(再)表示ユーザー制御JSTLを使用したデータ _fn:escapeXml_ または _c:out_

_<p><input type="text" name="foo" value="${fn:escapeXml(param.foo)}">
<p><c:out value="${bean.userdata}" />
_

_<table>_行とLoopTagStatusを交互に

JSTLのvarStatus属性 _c:forEach_ は、 LoopTagStatus を返します。これには、いくつかのゲッターメソッド( ELで使用されます!)したがって、偶数行を確認するには、loop.getIndex() % 2 == 0かどうかを確認します。

_<table>
    <c:forEach items="${items}" var="item" varStatus="loop">
        <tr class="${loop.index % 2 == 0 ? 'even' : 'odd'}">...</tr>
    <c:forEach>
</table>
_

最終的には

_<table>
    <tr class="even">...</tr>
    <tr class="odd">...</tr>
    <tr class="even">...</tr>
    <tr class="odd">...</tr>
    ...
</table>
_

CSSを使用して、背景色を変更します。

_tr.even { background: #eee; }
tr.odd { background: #ddd; }
_

リスト/配列からカンマ区切りの文字列にLoopTagStatusを入力します。

もう1つの便利な LoopTagStatus メソッドは isLast() です。

_<c:forEach items="${items}" var="item" varStatus="loop">
    ${item}${!loop.last ? ', ' : ''}
<c:forEach>
_

その結果、_item1, item2, item3_のようになります。


EL関数

_public static_ユーティリティメソッドをEL関数として宣言すると( JSTL functions など)、ELで使用できます。例えば。

_package com.example;

public final class Functions {
     private Functions() {}

     public static boolean matches(String string, String pattern) {
         return string.matches(pattern);
     }
}
_

_/WEB-INF/functions.tld_は次のようになります。

_<?xml version="1.0" encoding="UTF-8" ?>
<taglib 
    xmlns="http://Java.Sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://Java.Sun.com/xml/ns/javaee http://Java.Sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

    <tlib-version>1.0</tlib-version>
    <short-name>Custom_Functions</short-name>
    <uri>http://example.com/functions</uri>

    <function>
        <name>matches</name>
        <function-class>com.example.Functions</function-class>
        <function-signature>boolean matches(Java.lang.String, Java.lang.String)</function-signature>
    </function>
</taglib>
_

として使用することができます

_<%@taglib uri="http://example.com/functions" prefix="f" %>

<c:if test="${f:matches(bean.value, '^foo.*')}">
    ...
</c:if>
_

元のリクエストURLとクエリ文字列を取得する

JSPが転送されている場合、次の方法で元のリクエストURLを取得できます。

_${requestScope['javax.servlet.forward.request_uri']} 
_

と元のリクエストクエリ文字列、

_${requestScope['javax.servlet.forward.query_string']}
_

それはそれまででした。多分私は遅かれ​​早かれもう少し追加します。

153
BalusC