Oracle Containers for J2EE JavaServer Pages開発者ガイド 10g(10.1.3.1.0) B31860-01 |
|
この章では、JSPページのプログラミングに関する基本的な考慮事項について、例を示して説明します。JSPとサーブレット間の相互作用およびデータベース・アクセスについても説明します。
次の項目について説明します。
次の各項では、OC4J環境でJSPページのコーディングまたは使用を開始する前に考慮しておく必要がある事項について説明します。
サーブレット仕様(サーブレット2.2以降)に従って、各Webアプリケーションには独自のサーブレット・コンテキストがあります。各サーブレット・コンテキストは、サーバーのファイル・システム内でディレクトリ・パスに関連付けられています。このディレクトリ・パスは、Webアプリケーションのモジュール用のベース・パスです。このベース・パスがアプリケーション・ルートです。
各Webアプリケーションには、独自のアプリケーション・ルートがあります。標準のサーブレット環境のWebアプリケーションの場合、サーブレット、JSPページ、およびHTMLファイルなどの静的なファイルは、すべてこのアプリケーション・ルートに基づいています。(これに対して、サーブレット2.0環境では、サーブレットとJSPページのアプリケーション・ルートと、静的なファイルのドキュメント・ルートは異なります。)
サーブレットURLには、次の汎用的なフォームがあります。
http://host:port/contextpath/servletpath
サーブレット・コンテキストが作成されると、アプリケーション・ルートと、URLのコンテキスト・パス部分との間にマッピングが指定されます。サーブレット・パスは、アプリケーションのweb.xml
ファイルに定義されます。web.xml
内の<servlet>
要素によって、サーブレット・クラスがサーブレット名に関連付けられます。web.xml
内の<servlet-mapping>
要素によって、URLパターンが指定のサーブレットに関連付けられます。サーブレットが実行されると、サーブレット・コンテナは、指定されたURLパターンを既知のサーブレット・パスと比較し、一致したサーブレット・パスを選択します。詳細は、『Oracle Containers for J2EEサーブレット開発者ガイド』を参照してください。
たとえば、アプリケーション・ルートが/home/dir/mybankapp/mybankwebapp
のアプリケーションが、コンテキスト・パス/mybank
にマッピングされると仮定します。さらに、このアプリケーションには、サーブレット・パスがloginservlet
のサーブレットが含まれると仮定します。このサーブレットは、次のように起動できます。
http://host:port/mybank/loginservlet
アプリケーション・ルートのディレクトリ名はユーザーには表示されません。
このアプリケーションのHTMLページについてこの例を使用すると、次のURLによって、/home/dir/mybankapp/mybankwebapp/dir/abc.html
ファイルがポイントされます。
http://host:port/mybank/dir/abc.html
各サーブレット環境には、デフォルトのサーブレット・コンテキストもあります。このコンテキストのコンテキスト・パスは、デフォルトのサーブレット・コンテキストのアプリケーション・ルートにマッピングされている「/
」のみです。たとえば、デフォルトのコンテキストのアプリケーション・ルートが/home/dir/defaultapp/defaultwebapp
で、サーブレット・パスがmyservlet
のサーブレットでデフォルトのコンテキストを使用すると仮定します。その場合のURLは、次のとおりです。
http://host:port/myservlet
デフォルトのコンテキストは、URLに指定されているコンテキスト・パスと一致しない場合にも使用されます。
HTMLファイルについてこの例を使用すると、次のURLによって/home/dir/defaultapp/defaultwebapp/dir2/def.html
ファイルがポイントされます。
http://host:port/dir2/def.html
OC4JのWebコンテナは、Webサーバー上の標準の場所を使用して、変換済JSPページおよび必須クラス(JavaBeansなど)用の.class
ファイルと.jar
ファイルを検索します。コンテナは、Webサーバーのクラスパス構成を使用せずに標準の場所でファイルを検索します。
従属クラスの場所は次のとおりです。これらの場所はアプリケーション・ルートと相対的な関係があります。
/WEB-INF/classes/... /WEB-INF/lib
JSPページ実装クラス(変換済ページ)の場所は、次のとおりです。
.../_pages/...
/WEB-INF/classes
ディレクトリは、Javaの各.class
ファイル用です。これらのクラスは、Javaパッケージのネーミング規則に従って、classes
ディレクトリ下のサブディレクトリに格納する必要があります。たとえば、oracle.jsp.sample.lottery
パッケージに含まれるように定義した、LottoBean
と呼ばれるJavaBeanがあると仮定します。Webコンテナは、アプリケーション・ルートに対して相対的な次の場所で、LottoBean.class
を検索します。
/WEB-INF/classes/oracle/jsp/sample/lottery/LottoBean.class
lib
ディレクトリは、JAR(.jar
)ファイル用です。Javaパッケージ構造はJARファイル構造に指定されているため、すべてのJARファイルは、サブディレクトリ内ではなく、lib
ディレクトリ内に直接格納されます。たとえば、LottoBean.class
は、アプリケーション・ルートに対して相対的な次の場所にあるlottery.jar
に格納されます。
/WEB-INF/lib/lottery.jar
_pages
ディレクトリは、OC4JのJ2EEホーム・ディレクトリの下にあり、jsp-cache-directory
構成パラメータの値によって決まります。詳細は、「生成されるファイルとその格納場所」を参照してください。
OC4JのWebコンテナは、JSP仕様に基づいて次のパッケージをJSPページにデフォルトでインポートします。JSPでこれらのパッケージを使用する場合、page
ディレクティブのimport
設定は不要です。
javax.servlet.* javax.servlet.http.* javax.servlet.jsp.*
以前のリリースでは、次のパッケージもデフォルトでインポートされました。
java.io.* java.util.* java.lang.reflect.* java.beans.*
使用する未修飾のクラス名と、インポートしたパッケージ内の同じ名前のクラスとの間で発生する競合を最小化するために、インポートするデフォルトのパッケージ・リストが縮小されました。
ただし、このために、以前のバージョンのOC4Jで使用していたアプリケーションで移行上の問題が発生する可能性があります。このようなアプリケーションは、正常にコンパイルされない場合があります。デフォルト・リストのパッケージより多くのパッケージをインポートする必要がある場合は、次の2つの方法があります。
page
ディレクティブのimport
設定に指定します。詳細は、「ディレクティブ」の項のpage
ディレクティブについての説明を参照してください。複数ページの場合、デフォルト・リストより多いパッケージのインポートは、グローバル・インクルード機能を使用して実行できます。「Oracle JSPのグローバル・インクルード」を参照してください。
extra_imports
構成パラメータまたは事前変換用のojspc -extraImports
オプションを使用して指定します。構文は、OC4J構成パラメータ設定とojspc
オプション設定でそれぞれ異なります。必要に応じて次の項を参照してください。
OC4Jには、Sun社のJDK1.4およびJDK 1.5が同梱されています。したがって、以前のバージョンのJDKから移行する場合、次の点を考慮する必要があります。
Sun社が述べているように、コンパイラでは、不特定の名前空間から型をインポートするインポート文は拒否されます。これは、JDKの以前のバージョンに関するセキュリティ上の問題とあいまい性に対処するための措置でした。基本的に、これはパッケージに含まれていないクラス(クラスのメソッド)を起動できないことを示します。パッケージに含まれていないクラスを起動しようとすると、コンパイル時に致命的エラーが発生します。
これは特に、JSPページからJavaBeansを起動するJSP開発者に影響します。このようなBeanは、パッケージの外部にあることが多いためです(JSP仕様2.0では、新しいコンパイラの要件を満たすために、Beanはパッケージ内に存在することが必要です)。
JDK1.4の互換性の問題の詳細は、次のWebサイトを参照してください。
http://java.sun.com/j2se/1.4/compatibility.html
特に、「Incompatibilities Between Java 2 Platform, Standard Edition, v1.4.0 and v1.3」のリンクをクリックしてください。
この項では、特定のターゲット環境に関係なく、JSPページのプログラミング時に考慮する必要がある事項について説明します。次の項目について説明します。
JSP開発の主眼は、スクリプトレスなJSP、つまりスクリプトレットや実行時の式などの埋込みJavaスクリプト要素を含まないページの作成となっています。スクリプトレスなJSPは、従来のスクリプト・ベースのJSP開発と比べ、いくつかの利点があります。
JSPコードのサンプルは、スクリプトレスなJSPの例です。
JSP 1.1以来、ページの作成者は、JavaBeansおよびタグ・ハンドラ・インスタンスによって提供されるJava機能にアクセスするために、標準アクション・タグおよびカスタム・タグを活用することにより、ほとんどJavaを使用しないページを作成することが可能でした。ただし、完全にスクリプトレスなページを作成するには多くの課題がありました。たとえば、データ・アクセスの制限や、カスタム・タグ・ハンドラ・クラスを作成する際の複雑さなどです。
JSP 2.0リリースでは、いくつかの主要な改善点により、スクリプトレスなページの作成が大幅に容易になっています。たとえば、式言語(EL)機能をJSP仕様に完全に統合したことにより、ELからすべてのJSPページのコンテキスト・オブジェクト、変数およびリクエスト・パラメータ、さらにJavaBeansのプロパティとコレクション要素にアクセスできるようになりました。ELを使用すると、Javaスクリプトレットや式を使用せずに、アプリケーション・データにアクセスし、データを操作できます。式言語の詳細は、「式言語の使用によるJSP作成の単純化」を参照してください。
また、カスタム・タグを作成し、JSPページで使用する方法も容易になりました。JavaServer Pages標準タグ・ライブラリ(JSTL)では、JSP作成者が最も必要とする機能の大部分がカプセル化されているタグ・ライブラリを多数提供しています。新しいSimpleTagインタフェースにより、カスタム・タグ・ハンドラの作成が著しく単純化されました。実際、JSP作成者は、完全にJSP構文で作成されているタグ・ファイルを使用して、まったくJavaを使用しないタグ・ライブラリを作成できるようになりました。
JSP 2.0はJSP 1.xとの下位互換性を維持しています。つまり、JSP 2.0構文で作成されたページでも、Javaスクリプト要素を使用できます。
JavaServer Pagesテクノロジの主なメリットは、ビジネス・ロジックを含み、動的なコンテンツを決定するJavaコードと、リクエスト処理、プレゼンテーション・ロジックおよび静的なコンテンツを含むHTMLコードとを分離できる点です。この分離によって、HTMLのエキスパートはプレゼンテーションに集中でき、Javaのエキスパートは、JSPページからコールされるJavaBeansのビジネス・ロジックに集中できます。
標準のJSPページに含まれるのは、通常、リクエスト処理やプレゼンテーション用のJava機能に関する簡単なJavaコードのみです。たとえば、このサンプルのrunQuery()
メソッドでのデータ・アクセスは、JavaBeanで実行する方が適切です。ただし、出力をフォーマットするformatResult()
メソッドは、JSPぺージの方が適切です。
JSPページ内にJSPページをインクルードする方法は、2つあります。
include
ディレクティブ(「ディレクティブ」を参照)は、変換時にインクルード・ページのコピーを作成し、それをJSPページ(インクルード先ページ)にコピーします。この機能は、静的なインクルード(または変換時インクルード)と呼ばれ、次の構文を使用します。
<%@ include file="/jsp/userinfopage.jsp" %>
<jsp:include>
タグ(「標準のJSPアクション・タグ」を参照)は、実行時に、インクルード・ページの出力を、インクルード先ページの出力に動的に挿入します。この機能は、動的なインクルード(または実行時インクルード)と呼ばれ、次の構文を使用します。
<jsp:include page="/jsp/userinfopage.jsp" flush="true" />
C構文の知識がある方にとって、静的なインクルードは#include
文に相当します。動的なインクルードは、ファンクション・コールと同じです。いずれのインクルードも便利ですが、異なる目的で使用されます。
静的なインクルードの場合は、インクルード先のJSPページで生成されるコードのサイズが大きくなります。これは、変換時にinclude
ディレクティブの時点で、インクルード・ページのテキストが、インクルード先ページに物理的にコピーされるためです。1つのページが複数回、インクルード先ページにインクルードされると、複数のコピーが作成されます。
静的にインクルードされたJSPページは、独立した変換可能なエンティティである必要はありません。このページは、インクルード先ページにコピーされるテキストのみで構成されます。インクルード・テキストがコピーされたインクルード先ページは、変換可能であることが必要です。インクルード先ページは、インクルード・ページがコピーされる前に変換可能である必要はありません。静的にインクルードされた一連のページは、それ自体では独立できないフラグメントとなる可能性があります。
動的なインクルードでは、リクエスト・ディスパッチャなどへのメソッド・コールが増加しますが、インクルード先ページで生成されたコードのサイズが大幅に増加することはありません。動的なインクルードによって、実行時の処理は、インクルード先ページからインクルード・ページに切り替えられます。これは、インクルード・ページのテキストをインクルード先ページに物理的にコピーする処理とは逆になります。
動的なインクルードの場合は、リクエスト・ディスパッチャへの追加コールのため処理のオーバーヘッドが増加します。
動的にインクルードされたページは、それ自体で変換および実行できる独立したエンティティであることが必要です。インクルード先ページも同様に、動的なインクルードなしに変換および実行できる独立したエンティティであることが必要です。
静的なインクルードはページのサイズに影響を与え、動的なインクルードは処理のオーバーヘッドに影響を与えます。静的なインクルードの場合は、動的なインクルードに必要なリクエスト・ディスパッチャのオーバーヘッドを回避できますが、大規模なファイルの場合に問題が生じる可能性があります。(生成されたページ実装クラスのサービス・メソッドのサイズは、64KBに制限されています。)
また、静的なインクルードの過度の使用は、JSPページのデバッグを困難にする可能性があるため、プログラムの実行をトレースすることがさらに困難になります。静的にインクルードしたページ間でのわかりにくい相互依存は避けてください。
静的なインクルードは通常、そのコンテンツが複数のJSPページで繰り返し使用される、小規模なファイルをインクルードするために使用します。次に例を示します。
動的なインクルードは、モジュール方式のプログラミングに役立ちます。1つのページを、独立して実行したり、別のページの出力の一部を生成するために使用できます。動的にインクルードされたページは、インクルード先ページのサイズを増やさずに、複数のインクルード先ページで再利用できます。
リリース10.1.3.1より、OC4Jでは、J2EE 5.0およびJSP 2.1の仕様で定義されているJSPタグ・ライブラリでの注釈のサポートを開始しました。
J2SE 5.0以上では、構成データおよび依存性を、Javaコードの外部リソースにメタデータとして指定できます。これを、注釈とも言います。このようなデータを、構成ファイル、またはサービス(EJBやWebサービスなど)およびリソース参照(データソースやJMS宛先など)の注釈で定義できます。
次の制約に注意してください。
tags_reuse_default
パラメータのruntime
値は推奨されていません。そのため、推奨されていないruntime
の値をtags_reuse_default
パラメータで使用する場合、注釈はサポートされません。
jsp-taglib-locates
で定義されているタグ・ライブラリ)ではサポートされません。注釈は、アプリケーション内で使用されるタグ・ライブラリでのみサポートされています。
次の注釈はJavaServer Pagesでサポートされています。
次の注釈は、サーブレットではサポートされていますが、JavaServer Pagesではサポートされていません。
前述の例を除き、JavaServer Pagesでサポートされている注釈は、サーブレットでサポートされているものと同じです。これは『Oracle Containers for J2EEサーブレット開発者ガイド』の第7章「サービスおよびリソース参照の注釈の使用」に記載されています。
JSPアプリケーションの全般的な管理や監視に、アプリケーションの各ページからインクルードする集中チェッカ・ページを使用すると便利です。集中チェッカ・ページは、各ページの実行中に次のタスクを実行できます。
この他にも多くの使用方法があります。
たとえば、HttpSessionBindingListener
インタフェースを実装したセッション・チェッカ・クラスのMySessionChecker
があります。
public class MySessionChecker implements HttpSessionBindingListener { ... valueBound(HttpSessionBindingEvent event) {...} valueUnbound(HttpSessionBindingEvent event) {...} ... }
たとえば、次のような内容を含むチェッカ・ページ、centralcheck.jsp
を作成できます。
<jsp:useBean id="sessioncheck" class="MySessionChecker" scope="session" />
centralcheck.jsp
が含まれるページでは、セッション終了時にsessioncheck
がスコープ外になると同時に、サーブレット・コンテナが、MySessionChecker
クラスに実装されているvalueUnbound()
メソッドをコールします。これは、セッション・リソースを管理するために実行されます。centralcheck.jsp
は、アプリケーションの各JSPページの最後に含めることができます。
JSPページに大量の静的なコンテンツ(実行時に変更されるコンテンツのない大量のHTMLコード)が含まれると、変換と実行の速度が低下する場合があります。
2つの対処方法があり、いずれの対処方法でも変換速度は向上します。
jsp:include
タグを使用して、実行時にその出力をJSPページ出力にインクルードします。jsp:include
タグの詳細は、「標準のJSPアクション・タグ」を参照してください。external_resource
構成パラメータを有効にすると、JSPトランスレータがこの操作を実行します。このパラメータの詳細は、「JSP構成パラメータの概要」を参照してください。
事前に変換する場合は、ojspc
ツールの-extres
オプションが同じ機能を提供します。
大量の静的なコンテンツを含むJSPページ、または大量のタグ・ライブラリを使用するJSPページで起こりうるもう1つの問題は、ほとんど(全部ではない場合)のJVMでは、単一のメソッド内のコード・サイズが64 KBに制限されていることです。javac
によるコンパイルは可能ですが、JVMでは実行できません。実質的にJSPページのソース・ファイル全体から生成されたJavaコードは、ページ実装クラスのサービス・メソッドに追加されるため、この問題は、JSPトランスレータの実装によっては、JSPページに関する問題になる可能性があります。Javaコードは静的なHTMLをブラウザに出力するために生成され、スクリプトレットからのJavaコードは直接コピーされます。
同様に、JSPページのJavaスクリプトレットのサイズが大きいため、サービス・メソッドでサイズ制限の問題が発生する場合があります。ページ内のJavaコードが問題の原因の場合は、コードをJavaBeansに移動する必要があります。
大量のタグ・ライブラリの使用によってJSPページのサイズが制限される場合、ページを複数のページに分割し、必要に応じてjsp:include
タグを使用するという解決策が一般的です。
「スクリプト要素」で、メンバー変数の宣言にはJSPの<%! ... %>
宣言を使用し、メソッド変数は<% ... %>
スクリプトレットで宣言する必要があることを説明しました。
変数の使用方法に応じて、適切な機能を使用して宣言するように注意してください。
<%! ... %>
JSP宣言構文内で宣言される変数は、JSPトランスレータが生成したページ実装クラス内のクラス・レベルで宣言されます。この場合、オブジェクト・インスタンスを宣言すると、そのオブジェクトは複数のリクエストから同時にアクセスできます。したがって、page
ディレクティブ内でisThreadSafe="false"
が宣言されていないかぎり、オブジェクトはスレッド・セーフであることが必要です。
<% ... %>
JSPスクリプトレット構文内で宣言される変数は、ページ実装クラスのサービス・メソッドに対してローカルです。メソッドがコールされるたびに、変数またはオブジェクトのインスタンスが個別に作成されるため、スレッド・セーフティは必要ありません。
次にdecltest.jsp
の例を示します。
<HTML> <BODY> <% double f2=0.0; %> <%! double f=0.0; %> Variable declaration test. </BODY> </HTML>
この場合、ページ実装クラスのコードは次のようになります。
package ...; import ...; public class decltest extends ... { ... // ** Begin Declarations double f=0.0; // *** f declaration is generated here *** // ** End Declarations public void _jspService (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { ... try { out.println( "<HTML>"); out.println( "<BODY>"); double f2=0.0; // *** f2 declaration is generated here *** out.println( ""); out.println( ""); out.println( "Variable declaration test."); out.println( "</BODY>"); out.println( "</HTML>"); out.flush(); } catch( Exception e) { try { if (out != null) out.clear(); } catch( Exception clearException) { } finally { if (out != null) out.close(); } } }
この項では、次のpage
ディレクティブの特性について説明します。
page
ディレクティブは静的で、変換時に効果があります。パラメータ設定が実行時に評価されるようには指定できません。
page
ディレクティブのJava import
設定は、JSPページまたは変換単位内に累積されます。
page
ディレクティブは静的で、変換時に解析されます。動的な設定を実行時に解析するようには指定できません。次に例を示します。
次のpage
ディレクティブは有効です。
<%@ page contentType="text/html; charset=EUCJIS" %>
次のpage
ディレクティブは無効で、エラーが発生します。(この例ではEUCJIS
がハードコードされていますが、実行時に動的に決定されるすべてのキャラクタ・セットに当てはまります。)
<% String s="EUCJIS"; %> <%@ page contentType="text/html; charset=<%=s%>" %>
一部のpage
ディレクティブ設定には、代替策があります。例2の場合は、コンテンツ・タイプを動的に設定できるsetContentType()
メソッドを使用できます。
JSP仕様では、複数のディレクティブ属性(page
ディレクティブのimport
属性を除く)が単一のJSP変換単位(JSPページおよびinclude
ディレクティブを使用してインクルードされたページ)内で異なる値で再設定されていないことを、Webコンテナが確認する必要があることが記載されています。
ディレクティブ属性の重複設定が許可されているJSP標準に対する下位互換性のために、OC4Jではforgive_dup_dir_attr
構成パラメータが提供されています。JSP 2.0では、異なる属性が異なる値を持つ場合のみ、このパラメータを設定する必要があります。このパラメータの詳細は、「JSP構成パラメータの概要」を参照してください。たとえば、以前にコーディングしたページには、page
ディレクティブのlanguage
属性がすべてjava
に設定されているセグメントが複数含まれている可能性があります。
属性の重複設定については、次の点に注意してください。
page
ディレクティブが許可されます。 次の例は有効です。
<%@ page buffer="none" %> <%@ page session="true" %>
または
------------------------------ <%@ page buffer="0kb" %> <%@ include file="b.jsp" %> ------------------------------ ------------------------------ b.jsp <%@ page session="false" %> ------------------------------
ただし、この例では、forgive_dup_dir_attr
パラメータを設定する必要があります。
<%@ page buffer="none" %> <%@ page buffer="0kb" %>
または
<%@ page buffer="none" buffer="0kb" %>
または
------------------------------ <%@ page buffer="0kb" %> <%@ include file="b.jsp" %> ------------------------------ ------------------------------ b.jsp <%@ page buffer="3kb" %> ------------------------------
include
ディレクティブを使用してインクルードされたページで構成されていますが、jsp:include
タグを使用してインクルードされたページは含まれていません。jsp:include
タグを使用してインクルードされたページは、変換時に静的にインクルードされるのではなく、実行時に動的にインクルードされます。詳細は、「静的なインクルードと動的なインクルードの使用の比較」を参照してください。したがって、次の場合は許可されます。
------------------------------ <%@ page buffer="0kb" %> <jsp:include page="b.jsp" /> ------------------------------ ------------------------------ b.jsp <%@ page buffer="3kb" %> ------------------------------
page
ディレクティブのimport
属性には、属性の重複設定に対する制限は当てはまりません。
Java仮想マシン(JVM)では、Javaメソッド当たりのコード量を64K(65536バイト)に制限しています。アプリケーションで大きなJSPを使用すると、実行時にこの制限を超える可能性があります。一般的に、JSPのファイル・サイズは最小限にとどめる必要があります。
JSPで大量のタグ・ライブラリを使用する場合、「アプリケーション」→「JSPコンテナのプロパティ」→「カスタム・タグのコード・サイズの削減」プロパティ(またはglobal-web-application.xml
のreduce_tag_code
構成パラメータ)を有効にして、カスタム・タグから生成されるコードのサイズを削減します。ただし、これにより、JSPコンパイルのパフォーマンスが影響を受ける可能性があります。
サーブレット仕様では、JSPページのファイル名に拡張子.jsp
が必要です。ただし、サーブレット仕様2.3では、個別に変換可能な完全なページと、個別に変換できないページ・セグメント(include
ディレクティブを介して移入したファイルなど)の違いは識別されません。
JSP仕様2.0では、次のことをお薦めします。
.jsp
拡張子を使用します。
include
ディレクティブを介して導入したページ・セグメント(独自に変換できないファイル)には、.jsp
を使用しないでください。このようなファイルに対する拡張子の指定はありませんが、.jsph
、.jspf
または.jsf
の使用をお薦めします。
Webコンテナは通常、ソース・コードの空白(改行を含む)をブラウザへの出力内に保持します。開発者が意図しない空白が挿入される場合があるため、一般的に、JSPテクノロジは、バイナリ・データの生成には適していません。
次の2つのJSPページでは、ソース・コード内での改行の使用に応じて、異なるHTML出力が作成されます。
次のJSPページでは、Date()
コールとgetParameter()
コールの後に改行がありません。(Date()
コールで始まる3行目と4行目は、実際には1行のコードが折り返されています。)
nowhitsp.jsp
:
<HTML> <BODY> <%= new java.util.Date() %> <% String user=request.getParameter("user"); %> <%= (user==null) ? "" : user %> <B>Enter name:</B> <FORM METHOD=get> <INPUT TYPE="text" NAME="user" SIZE=5> <INPUT TYPE="submit" VALUE="Submit name"> </FORM> </BODY> </HTML>
このコードによるブラウザへのHTML出力は、次のとおりです。日付の後に空白行はありません。
<HTML> <BODY> Tue May 30 20:07:04 PDT 2000 <B>Enter name:</B> <FORM METHOD=get> <INPUT TYPE="text" NAME="user" SIZE=5> <INPUT TYPE="submit" VALUE="Submit name"> </FORM> </BODY> </HTML>
次のJSPページでは、Date()
コールとgetParameter()
コールの後に改行があります。
whitesp.jsp
:
<HTML> <BODY> <%= new java.util.Date() %> <% String user=request.getParameter("user"); %> <%= (user==null) ? "" : user %> <B>Enter name:</B> <FORM METHOD=get> <INPUT TYPE="text" NAME="user" SIZE=5> <INPUT TYPE="submit" VALUE="Submit name"> </FORM> </BODY> </HTML>
このコードによるブラウザへのHTML出力は、次のとおりです。
<HTML> <BODY> Tue May 30 20:9:20 PDT 2000 <B>Enter name:</B> <FORM METHOD=get> <INPUT TYPE="text" NAME="user" SIZE=5> <INPUT TYPE="submit" VALUE="Submit name"> </FORM> </BODY> </HTML>
次の理由から、JSPページはバイナリ・データの生成には適していません。通常は、かわりにサーブレットを使用します。
JspWriter
クラスには実際のバイトを書き込むためのメソッドがありません。
.gif
ファイルなど)の生成など、空白が重要な場合には適していません。 次に一般的な例を示します。
... <% response.getOutputStream().write(...binary data...) %> <% response.getOutputStream().write(...more binary data...) %>
この場合、ブラウザは、出力バッファのバッファリングに応じて、バイナリ・データの途中または最後にある不要な改行文字を受け取ります。コードの行間で改行を使用しないことによってこの問題は回避できますが、この方法は望ましいプログラミング・スタイルではありません。
JSPテクノロジは、動的なテキスト・コンテンツのプログラミングの簡素化を目的としているため、JSPページでバイナリ・データの生成を試行すると、JSPテクノロジの特性を失うことになります。
次の各項では、OC4JにデプロイするJSPページを開発する際、考慮すべきベスト・プラクティスについて説明します。
HTTPセッションは、メモリーの使用量により、Webアプリケーションにパフォーマンス面でのオーバーヘッドを追加します。セッションは、JSPではデフォルトで有効になっています。
HTTPセッション・オブジェクトが不要な場合は、使用しないでください。JSPページでHTTPセッションが不要な場合(基本的に、セッション属性の格納または取得が不要な場合)は、セッションを使用しないように指定できます。page
ディレクティブで、次のように指定します。
<%@ page session="false" %>
これによって、セッションの作成または取得のオーバーヘッドが減少するため、ページのパフォーマンスが改善されます。
デフォルトでは、サーブレットはセッションを使用しませんが、JSPページはセッションを使用します。
JSPでHTTPセッションを使用しない場合、必ずjavax.servlet.http.HttpSession.invalidate()
メソッドを使用して明示的に各セッションを取り消し、占有されているメモリーを解放します。
OC4Jでのデフォルトのセッション・タイムアウトは30分です。アプリケーションのweb.xml
ファイルで、<session-config>
要素の<session-timeout>
パラメータを設定することにより、特定のアプリケーションでこの値を変更できます。
ojspc
ユーティリティを使用した、デプロイ前のJSPページの事前変換を検討してください。JSPページにはユーザーが最初にアクセスするため、このユーティリティを使用すると、ページを変換するときのパフォーマンスの損失が発生しません。このユーティリティの詳細な使用方法は、第4章「ojspcによるJSPページのプリコンパイル」を参照してください。
分散可能なWebアプリケーションのJSPを作成している場合、HTTPセッションで変更されたオブジェクトを再設定するようページをコーディングし、セッション・オブジェクトの更新がクラスタ環境でレプリケートされることを確認してください。
OC4Jでは、セッションで保存されたセッション・オブジェクトをシリアライズ化しますが、オブジェクトのデータ・メンバーが変更されてもセッション・オブジェクトは再シリアライズ化されません。したがって、更新されたセッション状態はレプリケートされません。この問題はJSP特有のものではなく、サーブレットなどでも、セッションで変更されたオブジェクトを再設定する必要があります。
JSPでは、変更可能なセッション属性ごとに、HttpSession
に対してsetAttribute()
をコールするスクリプトレットを含めることにより、セッション状態を確実にレプリケートする必要があります。
<jsp:useBean>
タグを使用してsessionスコープBeanを作成する場合、setAttribute()
をコールしてセッションの更新されたBeanを再設定します。Beanの作成時にBeanに設定されたプロパティはセッションに対して設定されますが、Beanのプロパティ値の更新は設定されません。
JSPページのバッファを無効にします。デフォルトでは、JSPページはページ・バッファと呼ばれるメモリー領域を使用します。このバッファ(デフォルトは8 KB)は、動的なグローバリゼーション・サポートのコンテンツ・タイプの設定、転送またはエラー・ページをページで使用する場合に必要です。このような機能をページで使用しない場合は、page
ディレクティブのバッファを無効にできます。
<%@ page buffer="none" %>
これによって、メモリーの使用量が減少し、バッファをコピーする出力手順が不要になるため、パフォーマンスが改善されます。
1つのJSPページから別のページに制御を渡す方法は2つあります。<jsp:forward>
標準アクションタグを使用する方法と、スクリプトレットでリダイレクトURLをresponse.sendRedirect()
に渡す方法です。
<jsp:forward>
オプションの方が速く、効率的です。この標準アクションを使用すると、転送されたターゲット・ページはJSPランタイムによって内部的に起動され、継続してリクエストが処理されます。転送が実行されたことはブラウザに認識されず、ユーザーからは処理全体がシームレスに感じられます。
sendRedirect()
を使用すると、ブラウザはリダイレクトされたページに新しいリクエストを送信する必要があります。ブラウザに表示されるURLは、リダイレクトされたページのURLに変更されます。さらに、リダイレクトには新しいリクエストが含まれるため、すべてのrequestスコープのオブジェクトが、リダイレクトされたページで使用できなくなります。
ユーザーがページを再ロードする場合に、実行されている実際のページがURLに反映されるようにする場合のみ、リダイレクトを使用してください。
一部のJSPページをアプリケーションからのみアクセス可能にし、ユーザーが直接起動できないようにする場合があります。特に、Model-View-Controller(MVC)などのアーキテクチャで必要になる場合があります。
たとえば、フロントエンドまたは表示ページがindex.jsp
であるとします。ユーザーは、このページに直接アクセスするURLリクエストを介してアプリケーションを起動します。ここで、index.jsp
には、2番目のページのincluded.jsp
が含まれ、3番目のページのforwarded.jsp
に転送されるとします。さらに、ユーザーがURLリクエストを介してこれらのページを直接起動できないようにする必要があるとします。
これを行うには、included.jsp
とforwarded.jsp
をアプリケーションの/WEB-INF
ディレクトリに格納します。これらのページをこのディレクトリに格納すると、URLリクエストを介して直接起動できなくなります。直接起動しようとすると、ブラウザでエラー・レポートが生成されます。
index.jsp
ページの文は次のようになります。
<jsp:include page="WEB-INF/included.jsp"/> ... <jsp:forward page="WEB-INF/forwarded.jsp"/>
アプリケーション構造は次のようになります。構造には、サーブレット、JavaBeansまたは他のクラス用の標準のclasses
ディレクトリ、およびJARファイル用の標準のlib
ディレクトリが含まれます。
index.jsp WEB-INF/ web.xml included.jsp forwarded.jsp classes/ lib/
<orion-web-app>
要素のjsp-timeout
属性に、整数値(秒単位)を指定します。この値が経過した後にリクエストされなかった場合、そのJSPページはメモリーから削除されます。これによって、コール頻度の低いページに割り当てられているリソースが解放されます。デフォルト値は0
(ゼロ)で、タイムアウトはありません。 <orion-web-app>
属性は、OC4Jのglobal-web-application.xml
ファイルおよびorion-web.xml
ファイル内にあります。OC4Jインスタンス内のすべてのアプリケーションにタイムアウトを適用する場合、global-web-application.xml
ファイルを変更します。特定のアプリケーションの構成値を設定する場合、アプリケーション固有のorion-web.xml
ファイル内のファイルを変更します。
OC4Jでは、ファイルを直接適切な場所にコピーすることによるJSPページのデプロイをサポートしています。ページの開発やテストの際、この機能は大変便利です。
ただし、JSPベースのアプリケーションを本番用にリリースする場合、この方法はお薦めしません。必ずJSPファイルをEnterprise Archive(EAR)ファイルにパッケージ化して、標準的なデプロイおよび複数のアプリケーション・サーバーに渡るデプロイを可能にしてください。
デフォルトでは、JspWriterが出力/書込みのたびに動的なキャラクタ・セットをチェックします。パフォーマンス改善のため、OC4J全体のシステム・プロパティを-Dcheck.dynamic.charset="false"
に設定して、このチェックを無効にします。
これにより、キャラクタ・セットのチェックは、JspWriterでの出力/書込みごとではなく、リクエストごとに1回実行されます。
次の例には、JSPファイル内での誤った引用符の使用例が含まれています。
<td width="100%" style="border-left: 1px solid #000; border-right: 1px solid #000; <dhv:evaluate if="<%= !i.hasNext() %>">border-bottom: 1px solid #000;</dhv:evaluate>">
問題はstyle
属性の2つ目の引用符(if=
の後)です。
style="border-left: 1px solid #000; border-right: 1px solid #000; <dhv:evaluate if="<%= !i.hasNext() %>">border-bottom: 1px solid #000;</dhv:evaluate>">
Tomcatはこの正しくないコードを受け入れ、処理を続行します。
OC4JはJSPおよびサーブレットの仕様に従い、正しくないコードを受け入れず、エラーを発行します。
この問題を解決するには次を実行する必要があります。
内部属性値に対する引用文字の正しい使用例です。
<td width="100%" style="border-left: 1px solid #000; border-right: 1px solid #000; <dhv:evaluate if='<%= !i.hasNext() %>'>border-bottom: 1px solid #000;</dhv:evaluate>">
他にも引用符に関する問題があります。
プログラマがページの動的コンテンツに依存する外観を作成する場合があります。たとえば、個別に表の最終行を表示するとします。一部のライブラリはこれが可能であり、ライブラリをタグの属性内に含めて、周囲のタグがコールされる前に評価することができます。
Tomcatでは次のシーケンスを使用できます。
attribute="text"another text"text"
Tomcatでは、属性値が行の最初の引用符から最後の引用符までの単一の値として解析されます。
一方、OC4Jでは、属性値が最初の引用符と2つ目の引用符の間にある文字列textとして解析されます。後続の文字列another text"text"はエラーとみなされます。
正しくない使用方法:
<td width="100%" height="<dhv:evaluate if="<%= !i.hasNext() %>">20</dhv:evaluate>">
パーサーでの表示:
<td width="100%" height="<dhv:evaluate if=" <<-- ERROR Tag not closed!! <%= !i.hasNext() %>">20</dhv:evaluate>">
正しい使用方法:
<td width="100%" height="<dhv:evaluate if='<%= !i.hasNext() %>'>20</dhv:evaluate>">
JSPページのコーディングは多くの点で便利ですが、サーブレットのコールが必要な場合があります。その一例は、バイナリ・データを出力する場合です。
このため、サーブレットとJSPページ間での往復が、1つのアプリケーション内で必要になる場合があります。次の各項で、その方法を説明します。
あるJSPページから別のJSPページを起動する場合と同様に、jsp:include
操作タグとjsp:forward
操作タグを使用して、JSPページからサーブレットを起動できます。(「標準のJSPアクション・タグ」を参照。)次に例を示します。
<jsp:include page="/servlet/MyServlet" flush="true" />
ページの実行中にこの文が出現すると、ページ・バッファがブラウザに出力され、サーブレットが実行されます。サーブレットの実行が終了すると、制御がJSPページに戻されて、ページの実行が続行されます。この機能は、JSPページ間におけるjsp:include
操作タグと同じ機能です。
また、JSPページ間におけるjsp:forward
操作タグと同様に、次の文は、ページ・バッファをクリアし、JSPページの実行を終了して、サーブレットを実行します。
<jsp:forward page="/servlet/MyServlet" />
JSPページからサーブレットに動的にインクルードまたは転送を行う場合は、jsp:param
タグを使用して、サーブレットにデータを渡すことができます(別のJSPページへのインクルードまたは転送でも同様です)。
jsp:param
タグは、jsp:include
タグまたはjsp:forward
タグ内で使用できます。次に例を示します。
<jsp:include page="/servlet/MyServlet" flush="true" > <jsp:param name="username" value="Smith" /> <jsp:param name="userempno" value="9876" /> </jsp:include>
jsp:param
タグの詳細は、「標準のJSPアクション・タグ」を参照してください。
適切なスコープのJavaBean、またはHTTPリクエスト・オブジェクトの属性を使用して、JSPページとサーブレットとの間でデータの受渡しを行うこともできます。リクエスト・オブジェクトの属性の使用方法は、「JSPページとサーブレット間でのデータの受渡し」で説明します。
標準のjavax.servlet.RequestDispatcher
インタフェースの機能を使用すると、サーブレットからJSPページを起動できます。この機能を使用するには、次の手順に従ってコードを作成します。
ServletContext sc = this.getServletContext();
getRequestDispatcher()
メソッドへの入力として指定します。
RequestDispatcher rd = sc.getRequestDispatcher("/jsp/mypage.jsp");
この手順の実行前か実行中に、HTTPリクエスト・オブジェクトの属性を必要に応じて使用して、JSPページにデータを受け渡すことができます。詳細は、次項の「JSPページとサーブレット間でのデータの受渡し」を参照してください。
include()
メソッドまたはforward()
メソッドを起動し、HTTPリクエスト・オブジェクトとレスポンス・オブジェクトを引数として指定します。次に例を示します。
rd.include(request, response);
または
rd.forward(request, response);
これらのメソッドの機能は、jsp:include
タグおよびjsp:forward
タグの機能と同じです。include()
メソッドは一時的に制御を移すのみで、後で、起動したサーブレットに実行の制御が戻されます。
forward()
メソッドは、出力バッファをクリアすることに注意してください。
前の項の「サーブレットからのJSPページの起動」で説明したように、リクエスト・ディスパッチャを使用してサーブレットからJSPページを起動するとき、HTTPリクエスト・オブジェクトを必要に応じて使用して、データを受け渡すことができます。この操作は、次のいずれかの方法で実行できます。
name
=
value
のペアを持つ「?」構文を使用してリクエスト・ディスパッチャを取得すると、問合せ文字列をURLに追加できます。次に例を示します。
RequestDispatcher rd = sc.getRequestDispatcher("/jsp/mypage.jsp?username=Smith");
ターゲットのJSPページ(またはサーブレット)では、暗黙的なrequest
オブジェクトのgetParameter()
メソッドを使用すると、パラメータ・セットの値を取得できます。
setAttribute()
メソッドを使用できます。次に例を示します。
request.setAttribute("username", "Smith"); RequestDispatcher rd = sc.getRequestDispatcher("/jsp/mypage.jsp");
ターゲットのJSPページまたはサーブレットでは、暗黙的なrequest
オブジェクトのgetAttribute()
メソッドを使用すると、パラメータ・セットの値を取得できます。
この項では、前の各項で説明した機能を使用したJSPページとサーブレットのサンプルを示します。JSPページのJsp2Servlet.jsp
には、サーブレットのMyServlet
がインクルードされ、このサーブレットには別のJSPページのwelcome.jsp
がインクルードされます。
<HTML> <HEAD> <TITLE> JSP Calling Servlet Demo </TITLE> </HEAD> <BODY> <!-- Forward processing to a servlet --> <% request.setAttribute("empid", "234"); %> <jsp:include page="/servlet/MyServlet?user=Smith" flush="true"/> </BODY> </HTML>
import javax.servlet.*; import javax.servlet.http.*; import java.io.PrintWriter; import java.io.IOException; public class MyServlet extends HttpServlet { public void doGet (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { PrintWriter out= response.getWriter(); out.println("<B><BR>User:" + request.getParameter("user")); out.println (", Employee number:" + request.getAttribute("empid") + "</B>"); this.getServletContext().getRequestDispatcher ("/jsp/welcome.jsp").include(request, response); } }
<HTML> <HEAD> <TITLE> The Welcome JSP </TITLE> </HEAD> <BODY> <H3> Welcome! </H3> <P><B> Today is <%= new java.util.Date() %>. Have a nice day! </B></P> </BODY> </HTML>
この項では、JavaServer Pagesを含むアプリケーションをTomcatからOracle Application Server(OC4J)に移行する場合に使用するJSP固有のポインタを示します。TomcatからOC4Jへの移行に関する主な説明は、『Oracle Containers for J2EEサーブレット開発者ガイド』の第6章のアプリケーションのApache TomcatからOC4Jへの移行に関する項に記載されています。これには、TomcatからOC4JへのJSPコンパイルの問題に関する項も含まれています。
JSPページはTomcatからOracle Application Serverへ簡単に移行でき、Tomcat環境で選択した内容に応じて、コードの変更はほとんど必要ないか、あるいはまったく必要ありません。
Oracle Application Server 10gリリース3(10.1.3.1)は、Sun社のJavaServer Page仕様バージョン2.0に準拠しています。Tomcat 5.5も、バージョン2.0と互換性があります。TomcatとOracle Application Server Containers for J2EE(OC4J)の両方に同じバージョンのJava Server Pages仕様が実装されているため、コアJSP仕様の領域でこの2つに違いはありません。
また、Oracle Application Server 10gリリース3(10.1.3.1)は、バージョン1.2との下位互換性があります。そのため、標準のバージョン1.2仕様で作成されたJSPページは、Oracle Application Serverで正常に作動し、移行の手間は最小限で済みます。
JSPページを新しい環境に移行する場合の主なタスクは、構成とデプロイです。独自の拡張子を使用すると、追加のタスクが必要になり、移行が複雑になります。
JSPページの移行に関係するタスクは、JSPページのパッケージとデプロイの方法によっても異なります。JSPページは、単純なJSPページとして、標準ディレクトリ構造内でその他のリソースとともにパッケージされるWebアプリケーションとして(WARファイル)、またはEnterprise Application Archive(EAR)ファイルとしてデプロイできます。
TomcatからOC4JへのJSPページの移行は簡単で、移行タスクには構成、(WARファイルへの)パッケージおよび(適切なデプロイ・ディレクトリへの)デプロイが含まれます。これらのタスクは、手動あるいはOracle JDeveloperを使用して実行できます。
JSPページには、HTTPサーブレットのような特定のマッピングは必要ありません。単純なJSPページは、JSPページおよびJSPページに必要なすべてのファイルを適切なディレクトリにコピーすることでデプロイできます。その他の登録は必要ありません。
OC4Jのデプロイ・プロセスは、J2EE Webアプリケーションと様々な構成ファイルをデフォルトで提供することで簡略化されています。
単純なJSPページをTomcatからOC4Jへ移行する一般的な手順は、次のとおりです。
Oracle Enterprise Manager 10g Application Server Controlコンソールの「管理」Webページを使用するか、次のopmnctl
コマンド(ローカルで実行)を使用します。
opmnctl @instance startproc ias-component=OC4J
http://<hostname>:7777/j2ee/MyJspPage.jsp
<hostname>
は、JSPファイルをコピーしたOracle Application Serverのホストです。
JSPページの構成とデプロイの詳細は、『Oracle Containers for J2EE構成および管理ガイド』を参照してください。
JSPページはJSPコンパイラによって自動的にコンパイルされます。ただし、JSPページのテストおよびデバッグを行う場合は、直接JSPコンパイラにアクセスします。
JSPコンパイラは.jspファイルを解析して.javaファイルにします。次に、標準のJavaコンパイラを使用して.javaファイルを.classファイルにコンパイルします。
次のツールのいずれかを使用して、JSPページをプリコンパイルできます。
ojspc
という名前のOC4Jコマンドライン・ユーティリティ。 JSPページを実行してクライアント・リクエストを処理している間に、ページの内側または外側(コールされたJavaBean内など)で実行時エラーが発生する場合があります。この項ではエラー処理機能について説明し、基本的な例を示します。
この項では、実行時例外の処理機能について説明します。JSPエラー・ページを使用する場合についても説明します。
JSPページの実行中に発生した実行時エラーは、標準のJava例外処理機能によって、次のいずれかの方法で処理されます。
java.lang.Throwable
インスタンス)は、エラー・リソースに転送されます。JSPエラーは、この方法で処理することをお薦めします。この場合、エラーの情報を持つ例外インスタンスは、名前にjavax.servlet.jsp.jspException
を使用し、setAttribute()
コールを介して、request
オブジェクトに格納されます。
エラー・リソースのURLは、元のJSPページでpage
ディレクティブのerrorPage
属性を設定すると指定できます。(page
ディレクティブなどのJSPディレクティブの概要は、「ディレクティブ」を参照してください。)
デフォルトのエラー・リソースの詳細は、Sun社のJavaサーブレット仕様2.4を参照してください。
オプションとして、別のJSPページを、元のJSPページからの実行時例外のエラー・リソースとして使用する方法があります。JSPエラー・ページには、isErrorPage="true"
に設定するpage
ディレクティブが必要です。この方法で定義されたエラー・ページは、web.xml
ファイルで宣言されているエラー・ページよりも優先されます。
エラーの情報を持つjava.lang.Throwable
インスタンスは、エラー・ページでJSPの暗黙的なexception
オブジェクトを介してアクセス可能です。このオブジェクトにアクセスできるのはエラー・ページのみです。exception
オブジェクトなど、JSPの暗黙的なオブジェクトの詳細は、「暗黙的なオブジェクト」を参照してください。
元のJSPページにautoFlush="true"
(デフォルト設定)のpage
ディレクティブがあり、そのページのJspWriter
オブジェクトのコンテンツがレスポンスの出力ストリームにすでにフラッシュされている場合、取得されなかった例外をエラー・ページに転送しようとしても、レスポンスをクリアできない可能性があることに注意してください。一部のレスポンスは、ブラウザがすでに受信している可能性があります。
エラー・ページの使用例は、次の「JSPエラー・ページの例」の項を参照してください。
次のnullpointer.jsp
の例では、エラーを生成し、エラー・ページのmyerror.jsp
を使用して、暗黙的なexception
オブジェクトのコンテンツを出力します。
<HTML> <BODY> <%@ page errorPage="myerror.jsp" %> Null pointer is generated below: <% String s=null; s.length(); %> </BODY> </HTML>
<HTML> <BODY> <%@ page isErrorPage="true" %> Here is your error: <%= exception %> </BODY> </HTML>
この例では、次の内容が出力されます。
|
![]() Copyright © 2007 Oracle Corporation. All Rights Reserved. |
|