現在では、ほとんどのパソコンや携帯電話にはWebブラウザが搭載され、Webページが世の中にあふれています。ユーザはリンクをクリックしたり、URLを入力したりすることで、あるWebページを見ることができます。しかし、Webページの中には、ユーザがWebページに何かを入力して使うものもあります。一例として、Googleなどのサーチエンジンについて考えてみましょう。ユーザは次のようにしてGoogleを使うことでしょう。
サーチエンジンは、入力された言葉に関するWebページのリストを出力します。入力される言葉が違えば、当然ながら出力されるリストも変化します。ユーザからの入力によって出力結果が変化するので、このようなWebページは「動的な」Webページと呼ばれます。一方で、ユーザからの入力を必要としない普通のWebページは、「静的な」Webページと呼ばれることがあります。
サーチエンジンの他にも、ユーザからの入力が必要になるWebページがたくさんあります。
こうしたWebページは、すべて「ユーザがWebブラウザを使って何かを入力し、必要な結果を得る」という働きをします。この働きは、PCで動く通常のアプリケーションとよく似ています。そこで、先に挙げたようなWebページは「Webアプリケーション」と呼ばれることがあります。
先に述べたように、Webアプリケーションは、インターネット上ではもちろん、イントラネットでもよく使われています。その理由は何でしょうか?
それは、Webが十分に普及しており、取り扱いも楽だからです。
Webアプリケーションを使う側にとっては、それこそどこにでもあるWebブラウザを使ってURLを呼び出すだけで、Webアプリケーションを使えます。特定のソフトウェアをインストールする必要はありません。また、Webブラウザの操作は簡単です。
Webアプリケーションを提供する側にもメリットがあります。まず、既にあるApacheなどのWebサーバをそのまま利用できます。またWebアプリケーションはWebサーバ上に置かれています。そのため、各ユーザのコンピュータにアプリケーションをインストールする必要がなく、サーバ上で集中管理できるので、機能を追加したりバグを修正したりといったメンテナンスが楽になります。
Webアプリケーションでは、図1.1[3層モデル]のような「3層モデル(three-tier model)」という仕組みがよく利用されます。これは、Webアプリケーションに必要な機能を3つに分けたものです。
左側の層はクライアントです。WebアプリケーションではWebブラウザを用います。ユーザは、WebブラウザからあるURLを呼び出すだけで、アプリケーションを利用できます。
中間の層では、Webサーバが動いています。Apacheが代表的ですね。また、Webサーバの中に、「Webコンテナ(あるいはサーブレットコンテナ)」と呼ばれるものが組み込まれており、後述するServletやJSPはこのWebコンテナ内で動いています。
右側の層はデータベースです。多くのWebアプリケーションでは、さまざまなデータを取り扱います。そのために、データベースを利用するのが良い場合が多くなります。
先に見たように、Webアプリケーションでは、ユーザからの入力があると、その入力に応じたページを「動的に」作成しなければいけません。
Javaを使ったWebアプリケーションでは、Webブラウザからのリクエストを処理して動的なページを作成するため、ServletとJSPを使います。
Servletは、HttpServletというクラスを継承して、必要なメソッドをオーバーライドしたクラスです。CGIと同じように、プログラムからHTMLを出力できます。
// Servlet の例 // フォームから入力された文字を出力します import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ServletTest extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doIt(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doIt(request, response); } private void doIt(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("Shift_JIS"); response.setContentType("text/html; charset=Shift_JIS"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>ServletTest</title>"); out.println("</head>"); out.println("<body>"); out.println("<p>"); out.println("入力された文字は"); out.println(request.getParameter("title")); out.println("です"); out.println("</p>"); out.println("</body>"); out.println("</html>"); } }
JSPは、HTMLのソースにプログラムを埋め込んだものです。
<%@ page contentType="text/html; charset=Shift_JIS" %> <html> <body> <% for (int i = 1; i <= 5; i++) { %> <p>サンプル<%= i %></p> <% } %> </body> </html>
ServletとJSPは、先に述べたように「Webコンテナ」と呼ばれるものの内部で動きます。Webコンテナを使うことで、ユーザからのアクセスが増えても、プロセスは1つしか走らないので、処理が重くならないという利点があります。Jakarta Projectのオープンソースのコンテナである"Tomcat"が最も有名なWebコンテナです。
Webアプリケーションでは、通常のアプリケーションと同じようにデータを取り扱います。例えば、次のようなデータ処理となるでしょう。
こうしたデータは、たいていの場合、保存されている必要があります。商品の在庫リストが消えてしまったら、大変ですよね。データを保存して活用するには、データベース管理システム(DBMS)を通じてデータベースを使うのが便利な場合がほとんどです。
データベース管理システムを使うことによって、次に挙げるようなデータの管理に必要な処理を自動的に行ってくれます。
こうした処理を自分でプログラミングするのは、面倒な作業になります。そこで、データベースがよく利用されることになります。
Javaでは、"JDBC"という技術によってデータベースにアクセスします
Webアプリケーションでは、ユーザからの入力があると、その入力に応じたページを「動的に」作成しなければいけません。
Javaを使ったWebアプリケーションでは、Webブラウザからのリクエストを処理して動的なページを作成するため、ServletとJSPを使います。ServletとJSPは、「Webコンテナ」と呼ばれる環境の中で動作します。
JavaServer Pages (JSP)は、HTMLのソースに、特殊なタグとJavaプログラムを埋め込んだものです。JSPは、Webコンテナの内部でServlet (Javaプログラム)に変換されます。
リスト1.1[loop.jsp]がJSPのサンプルです。先頭に<%@と%>というタグがあります。また、<%と%>のタグに囲まれた部分と、<%=と%>に囲まれた部分にJavaのコードが埋め込まれています。
<%@ page pageEncoding="Shift_JIS" contentType="text/html; charset=Shift_JIS" %> <html> <head> <title>JSP: for 文を使ったサンプル</title> </head> <body> <% for (int i = 1; i <= 5; i++) { %> <p>サンプル<%= i %></p> <% } %> </body> </html>
<%と%>の間に、for文の一部が挟まれています。そして、for文のコードは途中で途切れ、HTMLタグが書かれています。もっとも、よく見ると<%= i %>のようにJavaプログラムの断片が埋め込まれています。その後に、<% } %>という部分があります。これは、先のfor文の始まりとなる中括弧"{"に対応した、閉じの中括弧"}"なのです。この例では、for文の条件に従って、
<p>サンプル<%= i %></p>
の部分を繰り返し出力することになります。
<%= Javaの式%>の形は、式の取る値にtoString()メソッドを適用して得られる文字列に置き換わります。ここでの<%= i %>では、for文の変数iが1から5までの値になるので、それぞれ"1", "2", "3", "4", "5"という文字列に置き換わります。
このJSPページをloop.jspという名前で保存し、TomcatなどのWebコンテナに置いておきます。WebブラウザからこのJSPページにアクセスがあると、WebコンテナはJSPページに埋め込まれたコードを処理して、HTMLを生成します。この例では、次のようなHTMLが生成されます。
<html> <head> <title>JSP: for 文を使ったサンプル</title> </head> <body> <p>サンプル1</p> <p>サンプル2</p> <p>サンプル3</p> <p>サンプル4</p> <p>サンプル5</p> </body> </html>
ブラウザでは、次のように表示されます。
出力例: サンプル1 サンプル2 サンプル3 サンプル4 サンプル5
JSPで使われる要素について説明しましょう。
JSPページ全体に関わることについて定義します。
構文: <%@ ディレクティブ名 属性とその値 %> 例: <%@ page pageEncoding="Shift_JIS" contentType="text/html; charset=Shift_JIS" %> <%@ page import="java.util.Date" %> <%@ page import="java.text.DateFormat" %>
この例の1行目で、JSPページそのもののエンコーディングを指定しています。この例では、Shift_JISにしています。2行目で、生成されるページがHTMLであり、文字コードがShift_JISであることを指定しています。さらに、3行目と4行目で、java.util.Dateとjava.text.DateFormatの2つのクラスをインポートしています。
変数を宣言します。変換された後のServletでは、クラス中のフィールドとなります。
構文: <%! 宣言 %> 例: <%! int i = 0; %> <%! int a, b, c; %> <%! Circle c = new Circle(2.0); %>
最後のセミコロンを忘れないようにしましょう。
式を記述します。<%= Javaの式%>の形は、式が返す値にtoString()メソッドを適用して得られる文字列に置き換わります。セミコロンは付けません。
構文: <%= Javaの式 %> 例: いまは <br /> <%= df.format(d) %> <br />です。
プログラムを記述します。
構文: <% プログラム %> 例: <% String name = null; if (request.getParameter("name") == null) { %> <p>not found!</p> <% } else { foo.setName(request.getParameter("name")); } %>
現在の日時を表示する例です。
<%@ page pageEncoding="Shift_JIS" contentType="text/html; charset=Shift_JIS" %> <%@ page import="java.util.Date" %> <%@ page import="java.text.DateFormat" %> <html> <head> <title>JSP: 現在の日時を示すサンプル</title> </head> <body> <% Date d = new Date(); DateFormat df = DateFormat.getDateTimeInstance(); %> <p> いまは <br /> <%= df.format(d) %> <br />です。 </p> </body> </html>
スクリプトレットの中でDateFormat型のdfというインスタンスを作っています。次の部分で、df.format()メソッドを実行することによって、現在の日時を表示しています。
<%= df.format(d) %>
JavaBeansは、「プロパティ」と呼ばれるものをもつJavaクラスです。あるBeanが持つ「属性」を「プロパティ」と考えることができます。例えば、「1冊の本」を示すJavaBeansで、次のような情報をプロパティとして扱うことができます。
Javaのクラスでこうした情報を扱うには、クラス中のフィールドを利用するのが普通でしょう。つまり、クラス中のフィールドが「プロパティ」である、と考えるのが自然です。ところがプロパティは、クラスのフィールドとは関係ありません。
あるJavaBeansにtitleというプロパティがということは、titleというフィールドがあることを意味しません。setTitle()やgetTitle()というメソッドがあることによって、titleというプロパティが存在することになるのです。
つまり、メソッドがあるから、プロパティが存在するということになります。
getTitleというメソッドは、titleというプロパティの値を獲得するメソッドです。このメソッドを"getter"と言います。
public String getTitle() { return this.t; }
また、setTitleというメソッドは、titleというプロパティに値を設定するメソッドです。このメソッドを"setter"と言います。
public void setTitle(String title) { this.t = title; }
setter、getterとプロパティのネーミング・ルールは、次のように整理できます。getterは、"get"で始まる名前を持つメソッドで、setterは、"set"で始まる名前を持つメソッドです。"set","get"の後に続く文字列が、プロパティの名前に対応します。正確には、プロパティ名の先頭の文字を大文字にして、"set"や"get"の文字を加えたものが、setterとgetterになります。
setter名 = "set" + ( プロパティ名 )' getter名 = "get" + ( プロパティ名 )'
逆に言うとプロパティ名は、setter名やgetter名から、先頭の"set"、"get"を取り除いた文字列に対応します。
プロパティ名 = ( setter名から、先頭の"set"を取り除いたもの ) プロパティ名 = ( getter名から、先頭の"get"を取り除いたもの )
整理すると、表1.1[プロパティと setter, getter]のようになります。
プロパティ名 | title |
getter名 | getTitle |
setter名 | setTitle |
この例のgetTitleメソッドは、"t"というフィールドの値を返し、またsetTitleメソッドでは"t"というフィールドに値を設定しています。しかし、プロパティの名前は"title"なのです。プロパティ名はフィールド名とは関係ないことがわかります。
JSPのページからBeanを呼び出すには、useBeanタグを利用します。このタグによって必要なBeanのインスタンスを生成して、指定した名前をつけることができます。JSPは、このインスタンスをスクリプトレットなどで利用するとともに、setProperty, getPropertyタグを使ってBeanのプロパティにアクセスできます。
Beanのインスタンスを作ります。
id属性はBeanの名前で、scope属性でBeanの寿命を示します。class属性ではBeanのパッケージ名を含めたクラス名を記述します。
<jsp:useBean id="today" scope="page" class="jp.ac.wakhok.tomoharu.Today" />
scopeはBeanの寿命を示すもので、次の4つのいずれかの値が入ります。
Beanのyearプロパティの値を獲得しています。
<jsp:getProperty name="today" property="year" />
Beanのusernameプロパティに、"maruyama"という値を設定しています。
<jsp:setProperty name="mybean" property="username" value="maruyama" />
JSPからBeanを利用するサンプルを見てみましょう。ここでは、jp.ac.wakhok.tomoharu.TodayというBeanから、todayという名前のインスタンスが作られています。しかしここで大事なのは、このオブジェクトやそのメソッドではなく、このオブジェクトがyear, month, date, hour, minuteといった「プロパティ」を持つことです。このJSPページでは、これらのプロパティが、getPropertyタグで文字列として取り出されています。
<%@ page contentType="text/html; charset=Shift_JIS" %> <jsp:useBean id="today" scope="page" class="jp.ac.wakhok.tomoharu.Today" /> <html> <head> <title>現在の日時を表示します</title> </head> <body> <h1>現在の日時を表示します</h1> <hr> <ul> <li>年: <jsp:getProperty name="today" property="year" /> <li>月: <jsp:getProperty name="today" property="month" /> <li>日: <jsp:getProperty name="today" property="date" /> <li>時: <jsp:getProperty name="today" property="hour" /> <li>分: <jsp:getProperty name="today" property="minute" /> </ul> </body> </html>
このJSPページからの出力は、次のようになります。
* 年: 2003 * 月: May * 日: 13 * 時: 13 * 分: 51
JSPを記述する人は、Beanのプロパティにアクセスするタグを書くだけでよく、スクリプトレットを書かなくても済みます。
Beanであるjp.ac.wakhok.tomoharu.Todayのソースを示します。JSPページのプロパティとの関係を読み取ってください。
package jp.ac.wakhok.tomoharu; import java.util.Calendar; import java.util.Date; import java.io.Serializable; public class Today implements Serializable { private Calendar calendar; public Today() { calendar = Calendar.getInstance(); Date d = new Date(); calendar.setTime(d); } public int getYear() { return calendar.get(Calendar.YEAR); } public String getMonth() { int m = calendar.get(Calendar.MONTH); String[] months = new String [] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; return months[m]; } public int getDate() { return calendar.get(Calendar.DATE); } public int getHour() { return calendar.get(Calendar.HOUR_OF_DAY); } public int getMinute() { return calendar.get(Calendar.MINUTE); } public static void main(String args[]) { Today today = new Today(); System.out.println("年: " + today.getYear()); System.out.println("月: " + today.getMonth()); System.out.println("日: " + today.getDate()); System.out.println("時: " + today.getHour()); System.out.println("分: " + today.getMinute()); } }
JSPやServletを動かすには「Webコンテナ」(または「Servletコンテナ」)が必要になります。
Tomcatは、Apache Software Foundationが開発しているWebコンテナです。Javaで書かれています。Tomcatはオープンソースになっており、活発に開発が続けられています。
TomcatはApache HTTP Serverなどの既存のWebサーバに組み込んで使えるほか、Tomcat単独でもWebサーバとして使えます。
TomcatはJavaで動いているので、まずJ2SEがインストールされている必要があります。環境変数JAVA_HOMEがセットされているかどうかチェックしてください。もしセットされていなければ、J2SEがインストールされているフォルダを指定します。
次に、Tomcatをインストールします。
インストールされているJ2SEが5.0であった場合、インストールするTomcatはTomcat 5.5.xとなります。また、インストールされているJ2SEが1.4であった場合、インストールするTomcatはTomcat 5.0.xとなります。
インストールが終わったら、CATALINA_HOMEという環境変数を設定します。この環境変数の値は、Tomcatをインストールしたフォルダの絶対パス名になります。
ServletやJSPなどは、Webコンテナの内部で動きます。そのため、Tomcatの内部にServletやJSPを置く必要があります。
JSPページをTomcat上で動かすには、次のようにします。
まず、%CATALINA_HOME%/webappsフォルダの中に新たなフォルダを作成します。このフォルダの中にServletやJSPなどで構成されるWebアプリケーションが置かれます。ここでは、testという名前のフォルダを作成します。
JSPページは、testフォルダの中に配置します。
testフォルダ以下は、.warという拡張子を持つファイルにまとめることもできます。このファイルを「warファイル」と言います。warファイルは、jarファイルと同じフォーマットのファイルです。
testフォルダにloop.jspを追加したときのファイル構成は、次のようになります。
%CATALINA_HOME% -- webapps/ -- test/ | |-- loop.jsp
さらに、testフォルダの中に、WEB-INFというフォルダを作ります。
WEB-INF/classesフォルダには、Webアプリケーションが直接利用するファイルが入ります。コンパイルしたServletのクラスファイルはこのフォルダに格納します。
WEB-INF/libフォルダには、Webアプリケーションが利用するライブラリが入ります。
WEB-INF/web.xmlファイルは、Webアプリケーションの設定を記述するDeployment Descriptor (DD)ファイルです。XMLで記述されています。Servletを使うときには、このファイルにServletの情報を記述する必要があります。JSPの場合は、情報を記述する必要はありませんが、このファイルそのものが無ければ動作しません。
<?xml version='1.0' encoding='UTF-8'?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd" version="2.4"> <display-name>JSP_Samples</display-name> <description> JSP Samples </description> </web-app>
最終的なファイル構成は次のようになります。これで、JSPを動かす準備が整いました。
%CATALINA_HOME% -- webapps/ -- test/ | |-- WEB-INF/ --- web.xml | |- classes/ | |- lib/ |-- loop.jsp
JavaBeansを利用するときには、WEB-INF/classesディレクトリにBeanを配置します。
ここで気をつけなければいけないのは、Beanはパッケージに含まれている必要があるということです。Beanのパッケージ名に合わせてフォルダを作り、その中にBeanを配置します。この例のように、Beanがjp.ac.wakhok.tomoharuパッケージに属しているなら、WEB-INF/classes/jp/ac/wakhok/tomoharuにToday.classを配置します。
%CATALINA_HOME% -- webapps/ -- test/ | |-- WEB-INF/ --- web.xml | |- classes/ | |- lib/ |-- loop.jsp
まず、Tomcatを起動します。
Tomcatがlocalhost上の8080番ポートで動いているとします。
loop.jspには次のURLでアクセスします。
http://localhost:8080/test/loop.jsp