JSP/Servletの隠し機能 [終了しました]。
質問
私はJSP/Servletを書くときに使用されるトリックなどに興味があります。まずはこちらから。
私は最近、ある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>
どのように解決するのですか?
注:JSP/Servletの隠された機能というのは、なかなか思いつきません。私の意見では、「ベストプラクティス」という表現がより適切で、そのどれかを思いつくことができます。また、JSP/Servletを使った経験があるかどうかにもよります。何年も開発をしていると、これらの"隠された機能"を見なくなるものです。いずれにせよ、私が何年か前に発見した、多くのスターターが十分に認識していない小さな"ベストプラクティス"をいくつかリストアップしてみます。これらは、多くのスターターの目には、「隠れた機能」として分類されるでしょう。とにかく、これがそのリストです :)
JSP ページを直接アクセスから隠す
JSPファイルを
/WEB-INF
フォルダーに置くことで、例えば次のような直接のアクセスから効果的に隠すことができます。
http://example.com/contextname/WEB-INF/page.jsp
. この結果
404
. そうすると、それらにアクセスするには
RequestDispatcher
でアクセスするか
jsp:include
.
JSPのためのプリプロセスリクエスト
ほとんどの人はサーブレットの
doPost()
に
ポスト
-がリクエスト (フォームの送信) を処理することは知っていても、Servlet の
doGet()
メソッドを使って
プリ
-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です。で始まる引数のないメソッドが存在する場合、そのメソッドは
get
または
is
は、ELでアクセスするには十分すぎるほどです。例.
${bean['class'].name}
の値を返します。
bean.getClass().getName()
ここで
getClass()
メソッドは実際には
Object#getClass()
. ただし
class
はブレース表記で指定します。
[]
というのは、ここで述べたように
EL式言語におけるinstanceof check
.
${pageContext.session.id}
の値を返します。
pageContext.getSession().getId()
で有用な、a.o.
アプレットはサーブレットのインスタンスと通信できますか?
.
${pageContext.request.contextPath}
の値を返します。
pageContext.getRequest().getContextPath()
で有用な、a.o.
コンテキストのルート名を含まずに相対パスを使用するには?
ELはMapにもアクセスできる
次のような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 © <fmt:formatDate value="${date}" pattern="yyyy" /></p>
これは(現時点では)次のように表示されます: "著作権 © 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
. さらに一歩進んで、パス情報を
/
のパス情報を分割し、最初の部分のみを JSP ページの URL とし、残りの部分を "ビジネスアクション" とします (サーブレットを
ページコントローラ
). また、例えば
デザインパターン Webベースアプリケーション
.
ユーザー入力を再表示するには
${param}
暗黙のELオブジェクト
${param}
を参照する
HttpServletRequest#getParameterMap()
は、JSPのフォーム送信後にユーザの入力を再表示するために使用することができます。
<input type="text" name="foo" value="${param.foo}">
これは基本的に
request.getParameterMap().get("foo")
. また、例えば
サーブレットにフォームを送信した後、JSP で HTML フォームフィールドの値を保持するにはどうすればよいですか?
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
は
varStatus
属性は、JSTL
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
:
もうひとつの便利な
LoopTagStatus
メソッドは
isLast()
:
<c:forEach items="${items}" var="item" varStatus="loop">
${item}${!loop.last ? ', ' : ''}
<c:forEach>
この結果、次のようなものになります。
item1, item2, item3
.
EL機能
EL関数は
public static
ユーティリティ・メソッドをEL関数として宣言することができます(例えば
JSTL関数
のように)、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']}
今のところこれだけです。いずれまた追加するかもしれません。
関連
-
Serious: End event threw exception java.lang.reflect.InvocationTargetException at sun.reflect.GeneratedM
-
java オープンソースフレームワーク統合 Context initialization failed の共通エラー。
-
[解決済み] JSPページでサーブレットを呼び出す方法
-
[解決済み] JSP/Servletを使用してサーバーにファイルをアップロードするにはどうすればよいですか?
-
[解決済み】JSP 2を使用して、JSPファイル内のJavaコードを回避するにはどうすればよいですか?
-
[解決済み】JSF、Servlet、JSPの違いは何ですか?
-
[解決済み] JSTLをインストールするには?絶対 URI: http://java.sun.com/jstl/core は解決できません。
-
[解決済み] jsp の出力から空白を取り除く
-
[解決済み] ログアウト後に、以前に閲覧した保護されたページを表示しないようにする。
-
[解決済み] JSP/ServletのWebアプリケーションを国際化/ローカライズするには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Serious: End event threw exception java.lang.reflect.InvocationTargetException at sun.reflect.GeneratedM
-
java オープンソースフレームワーク統合 Context initialization failed の共通エラー。
-
[解決済み] デザインパターン Webベースアプリケーション【終了しました
-
[解決済み] 別のJSPファイルをインクルードする
-
[解決済み] jsp の出力から空白を取り除く
-
[解決済み] サーブレットにおけるdoGetとdoPost
-
[解決済み] ELで定数を参照するには?
-
[解決済み] ログアウト後に、以前に閲覧した保護されたページを表示しないようにする。
-
[解決済み] ドメインURLとアプリケーション名を取得するには?
-
コンテキストのルート名を含まずに相対パスを使用する方法は?