前回 は,J2EE(Java2 Platform,Enterprise Edition)(注1)の概要を説明し,「Hello, world!」を表示するサーブレットとJSP(注2)の簡単なサンプルを紹介しました。今回はサーブレットとJSPについて,もう少し詳しく見ていきましょう(図1)。

図1
サーブレットはHTTPリクエストに対応してメソッドを記述する
最初にサーブレットから解説します。というのも,JSPは特殊なサーブレットという位置付けにあたるからです。サーブレットの実体は,Webコンテナ(注3)によって呼び出されるJavaのクラスです。ユーザーが作成するサーブレットは,javax.servlet.http.HttpServletのサブクラスとして実装します(図2)(注4)。サーブレットをWebコンテナに配備(注5)すると,Webコンテナによってそのインスタンスが生成され(init( )メソッドを呼び出し初期化され),クライアントからのHTTPリクエスト(注6)を待つ状態になります。WebコンテナはHTTPリクエストを受け付けると,リクエストされたURLに対応したサーブレットのservice( )メソッドを呼び出します。HttpServletのservice( )メソッドは,HTTPのリクエスト種別に応じて,GETならdoGet( ),POSTならdoPost( )など,サブクラスで実装されたサービス・メソッドの実体を呼び出すので(注7)、開発者はdoGet( )メソッドなどからプログラムが始まるようにコードを実装することになるわけです(図3)。

図2

図3
サービス・メソッドは,引数としてHttpServletRequestオブジェクトとHttpServletResponseオブジェクトを受け取ります。HttpServletRequestオブジェクトは、呼び出したクライアントのIPアドレス,Webブラウザの種類vリクエストのパラメータなどをアプリケーションに提供します。一方HttpServletResponseオブジェクトは,HTTPの結果コード、日付などのHTTPヘッダー、HTMLドキュメントなどのHTTPボディをブラウザに戻すためのものです。サービス・メソッドは、HttpServletRequestを解釈して必要な処理を行い、結果をHttpServletResponseを通じてWebブラウザに返却するわけです。
サーブレットが値やセッション情報を保持するには
サーブレットを扱ううえで注意しておかなくてはならないのは「サーブレットは通常、スレッドセーフではない」ということです。スレッドとは、プロセスを分割したもの。つまり、一つのサーブレットのインスタンスを複数のブラウザからのリクエストに対して使いまわすことがある、ということです。Webコンテナそのものはマルチスレッドで複数のブラウザからのリクエストを処理しますが、リクエストがあるたびにサーブレットのインスタンスを作成することはせず、同じサーブレットのインスタンスのサービス・メソッドを呼び出します。そのため、開発者が作成するサーブレットが、クライアントのIDや名前などをサーブレットのフィールドに保存しておこうとすると、並列したリクエストがあったときに問題になります。例えば、次のような処理があったとしましょう。
- リクエスト1がサーバーに到達
- リクエスト1のためにservice( )メソッドを呼び出す
- リクエスト1のクライアント情報をフィールドに保存
- リクエスト2がサーバーに到達
- リクエスト2のためにservice( )メソッドを呼び出す
- リクエスト2のクライアント情報をフィールドに保存
- フィールドのクライアント情報をリクエスト1に送信
- フィールドのクライアント情報をリクエスト2に送信
ここで問題となるのは7)です。リクエスト1に対するレスポンスの中にサーブレットのフィールドに入っているはずのユーザー名を埋め込もうとすると、それはすでに5)でリクエスト2のユーザー名に変わってしまっているからです。では、リクエストに対応した値を保持したい場合にはどのようにすればよいのでしょう。
そこで、一般的に使われるのがHttpServletRequestオブジェクトです。HttpServletRequestオブジェクトは、クライアントからのリクエストの内容だけでなく、その属性(Attribute)としてリクエストにかかわる値を保存する機能も持っているからです。例えばリスト1のようなコードを書けば、setAttribute(String name, Object o)メソッドで何らかのキーとなる名前と値のセットを登録し、getAttribute(String name)メソッドで名前に対応した値を取得できます。
リスト1
protected void doGet(
HttpServletRequest req,
HttpServletResponse resp) {
String userName =
req.getParameter("username");
User user = queryUser(userName);
// 値を保存
req.setAttribute("user", user);
// 値を取得
user = (User)req.getAttribute("user");
~ 略 ~
実際のWebアプリケーションでは、ユーザーがログインしてからログアウトするまで、あるいはサイトを訪問してから去るまで、といった複数のリクエストにまたがって値を保持したいケースもあります。このような複数のリクエストにまたがった一連のユーザー操作を「セッション」と呼びます。本来、HTTPにはセッションという概念がありませんが、サーブレットにはHttpSessionという仕組みがあります。
HttpSessionは、getSession(boolean create)メソッドによって、「このリクエストが属しているセッションを取得する」という擬似的なセッションを作成します。(1)ログイン時やトップ・ページを表示する際などの「セッションの入り口」のリクエストを受けたときにセッションを作成する、(2)それ以外の時はセッションが開始されていなければ「セッションの入り口」に案内する、といった使い方をします。引数のbooleanをtrueにすると、「もしまだセッションが始められていないなら新しくセッションを開始する」ということになります。セッションへの名前と値の登録はsetAttribute(String name, Object o)メソッド、値の取得はgetAttribute(String name)メソッドを使います。
ただしHttpSessionオブジェクトには注意が必要です。ユーザーがログアウトしてセッションが終了するか、一定時間リクエストが来ないときにタイムアウトするまで、HttpSessionオブジェクトはWebコンテナ上に長時間保持されるオブジェクトだからです。データベースの巨大な検索結果などをHttpSessionに放り込んでしまえば、どんどんサーバー上のリソースを圧迫することになるでしょう。また、大量のリクエストを処理するために、Webコンテナを複数設置してクラスタリングを行う場合にもパフォーマンス上の問題となる場合があります。
したがって、プログラミングするうえで楽をするためにセッションにデータを保持するというのは危険です。ユーザー情報など、毎回必要になるデータや、セキュリティ上重要な情報だけを保持する場合にとどめるのが安全でしょう。
JSPはサーブレットに変換されて動く
では今度はJSPを見てみましょう。前回紹介したJSPのコードを,もう一度見てください(リスト2)。
リスト2
<%@ page contentType="text/html;charset=Shift_JIS" language="java" %>
<html>
<head>
<title>Example JSP</title>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="private" />
</head>
<body>
<h1>Hello, world!</h1>
<p>はじめてのJSPです。</p>
</body>
</html>
ほとんどただのHTML文書ですね。違うのは、1行目に<%@ page ~%>という見慣れないタグが入っていることぐらいです。このタグは「ページ指示子」と呼ばれるJSP要素の一つです。このほかにも、
前述のように、JSPはサーブレットの一種で、実行時にWebコンテナによってサーブレットに変換されて動作します。では、リスト2のexample.jspがどのようにサーブレットに変換されるかを観察してみましょう。J2EE SDKをインストールしたディレクトリをC:j2sdkee1.3.1とすると、C:j2sdkee1.3.1binにあるj2ee.batを実行してJ2EEサーバーを起動してください。前回example.jspは、C:j2sdkee1.3.1public_htmlに保存したので、Webブラウザで http://localhost:8000/example.jsp にアクセスすれば、JSPのプログラムが実行できるはずです。
ここで注目してほしい点があります。最初にJSPのプログラムにアクセスしたとき(Webブラウザに表示させたとき)、表示までにちょっと時間がかかるなと思いませんでしたか?
実はこのタイムラグは、JSPをサーブレットのJavaソース・ファイルに変換し、コンパイル/実行している時間なのです。2回目以降のアクセスではその作業が必要ないので、すばやく表示されるはずです。実験してみましょう。example.jspをテキスト・エディタで開いて、適当な文字列を追加するなどして保存し直してみます。そしてもう一度ブラウザからアクセスすると、表示までに時間がかかることがわかるはずです。でも2回目は早いですね?
JSPプログラムをコンパイルするかどうかは、JSPファイルのタイムスタンプ(最終更新日時)を見て判断します。変換したファイルが古くなっていれば自動的に再コンパイルするわけです(注8)。
実際にどのようなクラスに変換されているのかも確認してみましょう。C:j2sdkee1.3.1repository<マシン名>webディレクトリを見てください(注9)。example$jsp.javaとそれをコンパイルした結果であるexample$jsp.classがあるはずです。前者がexample.jspを変換したJavaソース・ファイル、後者がコンパイルしたファイルです。
JSPをデバッグするなら変換後のソース・ファイルを見よう
テキスト・エディタでJSPをサーブレットに変換したソース・ファイルexample$jsp.javaを開いてみましょう(リスト3)(注10)。
リスト3
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class index$jsp extends HttpJspBase {
~ 略 ~
public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
String _value = null;
try {
if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init();
_jspx_inited = true;
}
}
}
~ 略 ~
// HTML // begin [file="/index.jsp";from=(0,69);to=(12,0)]
out.write("rn<html>rn <head>rn <title>Example JSP</title>rn
<meta http-equiv="Pragma" content="no-cache" />rn
<meta http-equiv="Cache-Control" content="private" />rn
</head>rn <body>rn <h1>Hello, world!</h1>rn
<p>はじめてのJSPです。</p>rn </body>rn</html>rn");
// end
~ 略 ~
}
よく見ると、(1)の_jspService( )メソッドが処理の実体であることがわかります(注11)。HttpServletRequestとHttpServletResponseをパラメータにとることからもわかるように、Servletのserviceメソッドから呼び出されるようになります。(2)のコメントで囲まれた個所が、HTMLを実際に表示する部分です。out.write( )の引数部分を見てみると、スペースや改行位置まで含めて文字列として出力されているのがわかります。コメント中のfromとtoは、元のJSPファイルの何行目の何文字目から何行目の何文字目までを変換した結果かを表しています。
JSPの開発では、変換したJavaソースをコンパイルする部分で引っかかって、表示がうまくできないということがよくあります。また文字化けするケースもあります。そうしたトラブルが起きた場合は、変換結果のソース・ファイルを参照してみるといいでしょう。解決のヒントになることがあります。
サーブレットとJSPでオンライン書店のプログラムを作る
さて、解説編はこれでおしまい。ここからは、実際に手を動かしてサンプルのWebアプリケーションを作成してみましょう。次回以降も同じWebアプリケーションを題材にして、サーバーサイド・アプリケーションをどんどん成長させていきます。誌面の関係ですべてのコードを紹介することはできませんが、本誌Webサイトからファイルをダウンロードできるので、ぜひそちらもご覧ください。
サンプルWebアプリケーションの題材は、オンライン書店のWebサイトです。今回はサーブレットとJSPで書籍や雑誌などの取扱商品を一覧表示できるようにします。次回以降、データベースを作成して商品を検索する機能や、EJB(注12)を作成してオンライン発注を行う機能を追加していきます(図4)。

図4
今回の開発範囲は、トップ・ページから商品カテゴリを選択して商品一覧ページに移動するまでの機能です。普通でしたら商品情報やカテゴリの情報はデータベースにおくところですが、データベース・プログラミングは次回以降のお楽しみということにして、今回は簡単にpropertiesファイル(注13)に商品の情報を保存することにしましょう。ただし、データベースに移行した場合もプログラムには影響ができるだけ少ないように作成しておきたいので、ロジックとデータベース・アクセスは分離しておきます。もちろんJSPを使って、HTML表示とロジックも分離します。また、処理の種類ごとに個別のサーブレットを作成してもよいのですが、定型的な処理が入ってきたとき、一元的に扱えるようにするため、一つのサーブレットがリクエストを受け付けて処理を振り分ける、MVCモデル2(注14)を採用します。
Singletonパターンで処理を軽くする
まず、開発するJavaのクラスを順番に紹介しておきましょう(図5)。図の右側から説明していきます。BookとCategoryというクラスがあります。これらは商品情報で、今の時点ではなんの振る舞いも持たないクラスです。Bookは書名、価格、著者名などの情報、Categoryは英名と表示用名称、そのカテゴリに含まれるBookの配列を持っています。
CategoryManagerはCategoryの永続化(注15)をつかさどるクラスです。前述のように今回はデータベースを使わないので、このようなクラスが必要になります。本来ならBookの永続化をつかさどるBookManagerもあったほうが良さそうですが、現在の要件では必要がないため省略しています。CategoryManagerは、Categoryの全件取得(queryAllメソッド)、Categoryの名前指定による取得(queryByNameメソッド)の二つの操作をサポートします。また、デザイン・パターン(注16)のSingletonパターンを使って、常に一つだけのインスタンスが利用されるようになっています。CategoryManagerは、propertiesファイルに登録した情報を読み込むなど重い初期化処理を行います。また、マルチスレッドで動作したとしても、スレッドごとに異なる状態を持つ必要がありません。そこでSingletonパターンを適用して、インスタンスが一つだけ生成されることを保証するわけです。

図5
サーブレットからの制御で画面を変更する二つの方法
今回実装する処理は、「トップ・ページにカテゴリ一覧を表示する」と「カテゴリを指定して含まれる本の一覧を表示する」の2種類だけです。それぞれの処理の実体は、TopBeanクラス(TopBean.java)とBookSearchBeanクラス(BookSearchBean.java)に記述します。TopBeanクラスは、CategoryManagerを使ってカテゴリ一覧を取得しリクエストの属性に設定しておいてから(リスト4の(1)、RequestDispatcher#forward( )メソッド(注17)を呼び出して処理をtop.jspに引き継ぎます(2)。
リスト4(TopBean.java)
package examples;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class TopBean {
public static final String CATEGORIES = "categories";
public void exec (HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
CategoryManager cMgr = CategoryManager.getInstance();
Category[] cs = cMgr.queryAll(); //(1)
req.setAttribute(CATEGORIES, cs);
req.getRequestDispatcher("top.jsp").forward(req, res); //(2)
}
}
ちなみに、サーブレットから他の画面に移動させるテクニックには、ほかにHttpServletResponse#sendRedirect( )というメソッドがありますが、RequestDispatcher#forward( )メソッドとの間には大きな違いがあります。RequestDispatcher#forwardでは、リクエストはWebコンテナ内で引き継がれます。これに対してHttpServletResponse#sendRedirect( )では、いったんブラウザにレスポンスし、ブラウザはそれを見て指定のURLにリクエストを発行し直すのです。
BookSearchBeanクラスの処理で注目する必要があるのは、HttpServletRequest#getParameter( )メソッドを使って(リスト5の(1)、リクエストの内容に応じてカテゴリを変更している部分です。処理に応じてHTTPのパラメータを利用するわけです。
リスト5(BookSearchBean.java)
package examples;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class BookSearchBean {
public static final String CATNAME = "cn";
public static final String CATEGORY = "category";
public void exec (HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
CategoryManager cMgr = CategoryManager.getInstance();
Category c = cMgr.queryByName(req.getParameter(CATNAME)); //(1)
req.setAttribute(CATEGORY, c);
req.getRequestDispatcher("bookList.jsp").forward(req, res);
}
}
コンテキスト名でサーブレットを振り分ける
BookStoreServletは、すべてのリクエストを一括して受けて、リクエストの内容を見て処理を振り分けるクラスです。どのクラスに処理を割り振るかは、ブラウザから送られてくるURLを見て判断します。
「BookStoreServletなら、アクセスするURLはhttp://localhost:8000/servlet/examples.BookStoreServletに決まってるんじゃないの?」と思われるかもしれません。前回説明した内容から推察すると確かにその通りですが、実はサーブレットは「どのようなURLにアクセスされたときにどのサーブレットに処理を割り振るか」を設定できるのです。
BookStoreServletクラスで使っているHttpServletRequest#getRequestURI( )というメソッドは、http://hoge.hoge/foo/barというURLによってサーブレットが呼び出された場合に/foo/barという文字列を返します。続けてHttpServletRequest#getContextPath( )を使うと、サーブレットがWebコンテナに配置されているときのWebアプリケーションのコンテキスト名を得ることができます。コンテキスト名とは、Webアプリケーションにアクセスするための名前です。
一つのWebコンテナには、複数のWebアプリケーションを配備することができます。Webアプリケーションを制御するためのURI(注18)は有限の名前空間ですし、再利用性を高めるためにそれぞれのWebアプリケーション内でURIをハードコードすることは避けたくもあります。そこで、J2EEの仕様では、Webアプリケーションに対してアクセスするための基準となる名前=コンテキスト名を定義するようになっているのです。
例えばともに「Servlet1」という名前を持つWebアプリケーションを、二つ同時に同じWebコンテナに配備することを考えてみてください。http://hoge.hoge/Servlet1という名前しか割り当てられないとすると、そのURLでリクエストされたときに、どちらのWebアプリケーションのServlet1を起動すればよいのかわかりません。そこで、それぞれのWebアプリケーションにsample1とsample2というコンテキスト名をつけて配備すると、sample1のServlet1にアクセスするにはhttp://hoge.hoge/sample1/Servlet1、sample2のServlet1にアクセスするにはhttp://hoge.hoge/sample2/Servlet1のURLにアクセスすればよいことになるわけです。BookStoreServletの場合は、/コンテキスト名/bookListでアクセスされたらBookSearchBeanを、それ以外ならTopBeanを呼び出すようになっています。
スクリプトレットにJavaプログラムを直接書く
最後にJSPファイルであるtop.jspを見てみましょう(リスト6)。
リスト6(top.jsp)
<%@ page // (1)begin
contentType="text/html;
charset=MS932"
import="examples.*"
language="java" %>// (1)end
<% // (2)begin
Category[] categories = (Category[])request.getAttribute(
TopBean.CATEGORIES);
%> // (2)end
<html>
<head>
<title>オンライン書店 トップ</title>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="private" />
</head>
<body>
<h1>ようこそ オンライン書店へ!</h1>
<p>ご希望の商品カテゴリを選択してください</p>
<ul>
<% for(int i = 0; categories != null && i < categories.length; i++){ %> // (2)
<li><a href="bookList?<%=BookSearchBean.CATNAME%>=<%=
categories[i].getName()%>"><%=
categories[i].getNameForView()%></a></li>
<% } %> // (2)
</ul>
</body>
</html>
(1)の<%@ page ~%>で囲まれた部分は、前回のexample.jspとほとんど同じですね。一つ付け加えられているのが「import="examples.*"」という記述で、これは「このJSP内ではexampleパッケージをimportしますよ」という宣言です。Javaソースに変換される際にimport文に変換されます。
目新しいのが<% ~ %>の個所です(2)。このタグで囲まれた部分をスクリプトレットと呼び、Javaのプログラムをそのまま書くことができます。ここでは、TopBeanでHttpServletRequestにsetAttribute( )しておいたCategoryの一覧を取り出しています。取り出した内容を表示するためには、<%= ~ %>のタグを使っています。コンテンツに文字列を出力するためのタグです。
書籍一覧を表示するためのリンクは、bookList?<%=BookSearchBean.CATNAME%>=<%=categories[i].getName( )%> に対して張っています。BookSearchBeanで必要とするカテゴリ名を、HTTPパラメータとして埋め込んでいるわけです。
クラス・ファイルをサーバーにDeployしてみよう
さて,これらのコンポーネントからなるWebアプリケーションをJ2EEサーバーに配備してみましょう。前回と同様にjavacコマンドでソース・ファイル(.java)をクラス・ファイル(.class)にコンパイルしたら,作業用ディレクトリに図6のような構成でクラス・ファイルとJSPファイルを配置します。
アプリケーションの配備は,C:j2sdkee1.3.1bindeploytool.batの配備ツールを使います(図7)。まず関連するファイルを一括したWARファイル(注19)を作り,それらをEARファイル(注20)としてまとめ,最後に「配備」するのが大まかな作業手順です。

図6

図7
配備ツールをダブルクリックして起動させたら,[ファイル]-[新規]-[アプリケーション]を選択し,新規アプリケーションのファイル名をC:worksample200210.ear,表示名をsample200210としてください(図8)。了解をクリックして元の画面に戻ったら,メニューバーの左から4番目,地球のマークのボタンを押して「新規Webコンポーネントウィザード」を開始します。「WARファイル」というダイアログ(図9)で右下の「編集(E)...」ボタンをクリックすると,WARコンテンツ編集ダイアログが表示されるので,開始ディレクトリで作業用ディレクトリ(C:work)を指定し,上部のペインで「WEB-INF」ディレクトリを選択,「追加」ボタンをクリックし,下のペインにクラス・ファイルを追加します(図10)。了解をクリックして元の画面に戻ったら,次に進み,コンポーネント一般プロパティのダイアログで,サーブレット・クラスは「examples.BookStoreServlet」を選択して先に進みましょう(図11)。

図8

図9

図10

図11
次の画面をデフォルトのままにして進んだら,コンポーネントの別名(ブラウザからの呼び出し名)として,追加ボタンを押して「top」と「bookList」の二つの名前を入力します(図12)(注21)。これでサーブレットの設定はOKです。完了ボタンを押してウィザードを終了してください。元の画面に戻ったら,右側ペインの編集ボタンを押して再度WARコンテンツ編集ダイアログを表示させ,top.jspとbookList.jspも同様に追加します。ここまでで,EARファイルとそれに含まれるWebアプリケーションを一つ作成できました。それではこれらをJ2EEサーバーに配備してみましょう。
左側ペインの「sample200210」を右クリックし,コンテキストメニューから「配備」を選択します。ダイアログはデフォルトのまま次へ進み,Webアプリケーションのコンテキストルートを指定します。「WebApp1」の右側のカラムを編集して「sample」と入力し(図13),完了ボタンをクリックしてください。表示されたダイアログに「sample200210の配備が完了しました」と表示されたら,作業は終わりです(図14)。

図12

図13

図14
それではブラウザで, http://localhost:8000/sample/top にアクセスしてみてください。図15が表示されればWebアプリケーションは正常に稼働しています。コンピュータ関連書籍をクリックしてみてください。図16のように表示されましたか?

図15

図16
JSPのデザインを変えたり,propertiesファイルを編集したりしてdeployし直すときは,作業用ディレクトリで編集したあとに,WARコンテンツ編集ダイアログでファイルを追加し,アプリケーションを配備し直すといいでしょう。
これでやっと,サンプル・アプリケーションが稼働し始めました。現状ではカテゴリ一覧があるだけで,検索機能もなければ商品も買えません。こんなサイトじゃ,お客さんも立ち去ってしまいますよね。というわけで来月は,商品情報をデータベースに移行して,JDBC(注22)による商品検索機能・メンテナンス機能を実現する予定です。お楽しみに!
- 注1:J2EE(Java2 Platform、Enterprise Edition)は、米Sun Microsystemsが策定したJavaによる企業システム構築のための仕様。現在のバージョンは1.3.1。
- 注2:サーブレット(Servlet)とJSP(JavaServer Pages)は、J2EEに含まれるWebアプリケーション構築用のAPI。コンテナは、サーブレットなどのコンポーネントの入れ物。Webコンテナは、Web処理を行うソフトウエア・コンポーネントを扱う。
- 注3:コンテナは、サーブレットなどのコンポーネントの入れ物。Webコンテナは、Web処理を行うソフトウエア・コンポーネントを扱う。
- 注4:つまりユーザーが作成するサーブレットは、javax.servlet.http.HttpServletを継承している。
- 注5:配備(deploy)は、作成したコンポーネントをJ2EEサーバー内に配置し、サーバーがコンポーネントを実行できるように設定すること。配備ツールを使った配備の手順は後述。
- 注6:HTTPリクエストは、WebブラウザからのアクセスのようなHTTPを使った通信要求のこと。
- 注7:WebブラウザからのHTTPリクエストには、GET、POSTなどの種類がある。
- 注8:この動作はJ2EEサーバーの製品や設定による。自動再コンパイルを行わないように設定できる製品もある。なお、自動再コンパイルを行うと、クラス・ファイルとJSPファイルのタイムスタンプを比較するオーバーヘッドがかかるため、パフォーマンスに悪影響を与えることがある。そこで本稼働時には、自動再コンパイルを行わない設定にするのが普通だ。
- 注9:変換された結果のJavaソースを参照できるかどうか、どのディレクトリに保存されるかについても、製品や設定によって異なる。
- 注10:変換したファイルの文字コードはUnicode(UTF-8)である。
- 注11:このメソッドは、javax.servlet.Servletインタフェースを拡張したjavax.servlet.jsp.HttpJspPageインタフェースで宣言されている。
- 注12:EJB(Enterprise JavaBeans)は、Javaのコンポーネント仕様JavaBeansをサーバー側で使えるように拡張したもの。
- 注13:propertiesファイルは、サーバーの設定情報などを保存するJ2EE用のテキスト・ファイル。
- 注14:MVC(Model-View-Controller)モデル2は、Webアプリケーション用のコンポーネント構成モデル。詳しくは連載1回目(日経ソフトウエア2002年9月号)を参照。
- 注15:永続化は、ファイルやデータベースなど、メモリー以外にオブジェクトを保存すること。
- 注16:デザイン・パターンは、オブジェクト指向プログラミングを行ううえでひな形となる設計。
- 注17:あるクラスが持つインスタンス・メソッドを、クラスにひも付けながらクラス・メソッドと区別して表現したい場合、.(ドット)で区切るのではなく#(シャープ)で区切ることが多い。リスト4(2)のgetRequestDispatcher( )はRequestDispatcherのインスタンス・メソッドなので、ここではRequestDispatcher#forward( )と表記している。
- 注18:URI(Uniform Resource Identifier)は、リソースを一意に表現するためのURLの上位概念。
- 注19:WAR(Web Application Archive)ファイルは,サーブレット,JSP,それらが利用するクラス群,関連ファイルなどをまとめたもの。
- 注20:EAR(Enterprise Application Archive)は,複数のWARをまとめたもの。
- 注21:1文字目のスラッシュは自動的に補完されるので入力しなくてもいい。
- 注22:JDBCは、データベースとJavaプログラムを接続するAPI。