連載
» 2001年07月10日 00時00分 公開

快速MySQLでデータベースアプリ!(10):Servlet/JSP+MySQLでアプリケーションサーバ その3 (2/3)

[鶴長鎮一,MySQLユーザ会]

JSPとJavaBeansの連携

 ServletとJSPはいかがでしたか? 確かにJSPはServletに比べてHTMLの自由度が上がりました。しかし、デザイナーにとっては難解なJavaコードが多数埋め込まれることになり、完全にコンテンツ管理を任せるには一抹の不安が残ります。ただし、コンパイルの手間がかからないという点ではJSPに分があります。一方で、複雑な処理を行う場合はServletの方が使いやすい場面もあります。

 それなら、ほとんど変更を要しないプログラムのロジックの部分をJSPから切り離し、JSPは単に処理の結果表示のみと割り切った方が、サイトの管理の分業化に貢献できます。では、JSPから切り離されたロジックはどこで処理をさせるのでしょう? そこでJavaBeansの登場です。

 次にその一例として、JSPとJavaBeansの連携によるMySQLサーバの操作を見ていきましょう。

Loginページの作成

 IDとパスワードを入力し、パスワードが正しければ次のコンテンツに進めるLoginページを作成してみましょう。まず、下図のような構成を考えます。

図1 Loginページの仕組み 図1 Loginページの仕組み

 正しいIDとパスワードは、プログラムを簡略化するためJavaコードの中に埋め込むものとします。ではサンプルを見ていきましょう。

〜省略
<FORM ACTION="login.jsp" METHOD="POST" ENCTYPE="application/x-www-form-urlencoded">
〜省略〜
<INPUT TYPE="TEXT" NAME="id" SIZE="12">
〜省略〜
<INPUT TYPE="PASSWORD" NAME="pass" SIZE="12">
省略〜
リスト login.html

 上記のように<FORM ACTION=>でlogin.jspが指定されており、id、passにそれぞれHTML FORMの値がセットされることを覚えておいてください。

 では、ACTIONの指定先であるlogin.jspリスト10)の解説です。

 4〜6行目に新しいタグが使われています。

<jsp:useBean id="loginbean" scope="page" class="LoginBean" />
<jsp:setProperty name="loginbean" property="id" param="id" />
<jsp:setProperty name="loginbean" property="pass" param="pass" />

 <jsp:XXX 〜 />はアクションタグ(または単にタグ)と呼ばれるもので、XXXを入れ替えることでさまざまな活用ができます。ここで使用されているアクションタグの意味とフォーマットは次のようになります。

<jsp:useBean
    id="JavaBeanのインスタンス名"
    scope="有効範囲"
    class="JavaBeanをコンパイルしてできたclass名"
/>

 JavaBeanを呼び出し、インスタンス名で使用できるようにします。例えば今回のサンプルの場合、LoginBeanがXXXというメソッドを持っていた場合、loginbean.XXXとして使えます。そのインスタンスの有効範囲を決めるのがscope(スコープ)です。リスト10では、これをpageとすることでlogin.jspでのみの使用に限定しています。よって、login.jspの使用後、このloginbeanインスタンスは破棄されます。ちなみに、page以外ではrequest、session、applicationが使用できます(コラム:スコープ(有効範囲)について参照)。

コラム スコープ(有効範囲)について

 Servlet/JSPでは、変数またはオブジェクトをServlet/JSP実行後もサーバ側に格納させておくことができます。その変数の有効範囲(スコープ)は下記のように決められています(下へ行くほどスコープが狭くなっています)。

application 同じServlet/JSPコンテナ内(ここではTomcat)の範囲内

session   同じWebブラウザからのリクエスト

request   <jsp:forward〜>などで呼び出されたページ

page     同じページのみ

<jsp:setProperty
    name="JavaBeanインスタンス名"
    property="インスタンスの中のプロパティ(変数)"
    param="セットしたい値"
/>

 先ほど生成したJavaBeanインスタンス内の変数に、値をセットしたい場合に使用します。JavaBeanを作る際、内部変数にアクセスするために変数に対してsetXXXメソッドとgetXXXメソッドを作成します(必要な変数にのみ)。そのメソッドをsetPropertyで間接的に呼び出し、値をセットします。また、サンプルではlogin.htmlから渡されるHTML FORMの値を、param=""を指定することでHTML FORMの変数名をそのまま使っています。リスト10では、login.htmlのidの値をloginbeanインスタンスの変数idに直接当てはめています。

 いよいよ11行目からスクリプトレットが始まります。それもたった3行だけの。12行目でLoginBeanのconfirmメソッドを使い、先ほどの<jsp:setProperty 〜 />で当てはめたidとpassが正しいか確認します。正しければ“true”、間違っていれば“false”を返します。

if(loginbean.confirm()){

 trueが返された場合、14行目の

<jsp:forward page="welcome.html" />

で指定されたページ(welcome.htmlリスト11)に転送します。

 戻り値がfalseであれば18行目のアクションタグで

<jsp:forward page="login.html" />

として再びlogin.htmlに戻します。これだけのJavaコードだったらWebデザイナーにサイトの管理を任せても安心できますね。

 では次に肝心のJavaBeansであるLoginBean.javaリスト12)を見てみましょう。

 「JavaBeansというからどんなものかと思えば、普通のJavaコードじゃないか」と思われた方も多いと思います。宣言文やコンストラクタ、各メソッド式を備えた一般的なJavaコードです。強いて違いを挙げれば、変数がprivateで宣言されており、setXXXメソッドやgetXXXを通してのみアクセスできるようになっているということでしょうか。

 しかし、その違いこそが大きな特徴です。先ほどのlogin.jspの<jsp:setProperty 〜 />で間接的に呼び出されていたメソッドがまさにこれに当たります。そのため、メソッドの名前の付け方に少し制限があります。例えば、変数aaに値をセットしたい場合はsetAa、値を取り出したい場合はgetAaのように、変数名の頭文字を大文字にしたものに用途に応じてset、getを頭に付けます。ただし、LoginBean.javaリスト12)の中ではpassを取り出すメソッドは用意しませんでした。パスワードを取られてしまっては大変なことになってしまいます。

 では、実行してみましょう。login.jsp、login.html、welcome.htmlと使用する画像ファイルを$WEBAPP/ディレクトリに移動します。LoginBean.javaは下記のようにコンパイルし、$WEBAPP/WEB-INF/classesにclassファイルを移動します。

$ $JAVA_HOME/bin/javac LoginBean.java
$ mv LoginBean.class $WEBAPP/WEB-INF/classes/

 Webブラウザからhttp://Webサーバ/atmarkit/login.htmlでLoginページを呼び出します。IDとパスワードを入力したら認証開始をクリックし、動作を確認しましょう。今回のIDとパスワードはMySQLサーバへのアクセスで使用したものと同じ、

ID:test
Pass:test2001

となっています。

IDとパスワードをMySQLで管理させる

 上記のサンプルでは以下のような問題があります。

  1. IDとパスワードがコードの中に埋め込まれているため、容易に変更/追加ができない
  2. 実は、認証に失敗してもwelcome.htmlを直接URL指定すれば見えてしまう

 1の解決策として、MySQLサーバにIDとパスワードの管理をさせます。次に2の問題はwelcome.htmlもJSP化し、ページを表示するたびにパスワードの確認をさせるようにします。しかし、毎回パスワードを入力するのは手間なので、Servlet/JSPのセッション管理を活用します。

 では、まずデータベースの準備をします。下記のようなテーブルをATMARKITデータベースに作成します。

フィールド データ型 備考
id char(20) 主キー・空白不可
pass char(20) 空白不可
# mysql ATMARKIT
mysql> CREATE TABLE login (
-> id char(20) DEFAULT '' NOT NULL,
-> name char(20) DEFAULT '' NOT NULL,
-> PRIMARY KEY (id),
-> KEY k_pass (pass)
-> );
Query OK, 0 rows affected (0.00 sec)

 ついでに、IDとパスワードの登録も行いましょう。

mysql> INSERT INTO login values ("test",password("test2001"));
Query OK, 0 rows affected (0.00 sec)

 パスワードフィールドは、password()関数で暗号化し、一般表示できないようにしておきます。

mysql> SELECT * FROM login;
+-------+------------------+
| id    | pass             |
+-------+------------------+
| test  | 350fb7096305b0d8 |
+-------+------------------+
1 rows in set (0.00 sec)

 では、LoginBean.javaリスト12)を手直ししてLoginBean2.javaリスト13)を作成します。作成し直すのは、confirm()メソッドです。JDBCでMySQLに問い合わせる機能を付けます。

 MySQLサーバ接続のための処理がいくつか追加されています。まず、10〜15行目でMySQL接続のためのパスワード、ユーザー名などの変数宣言。

private String server   = "localhost"; //MySQLサーバ
private String db       = "ATMARKIT";  //
private String db_user     = "test";      //ユーザー名
private String db_pass     = "test2001";  //パスワード
private String db_url      = "jdbc:mysql://" + server + "/" + db + "?useUnicode=true&characterEncoding=EUC_JP";
private Connection con = null;

 26〜61行目でMySQLサーバへの問い合わせ処理とそれに伴うimport文の修正。この2つが追加されています。

 JavaBeanとして見た場合、LoginBeanもLoginBean2も、idとpassを放り込んだ後、その組み合わせが正しいか判定してtrueかfalseを返すという振る舞いは変わっていません。

 これで、パスワード管理をMySQLサーバで行えるようになりました。次に、不正にwelcome.htmlにアクセスされないように変更してみましょう。まずはHTML FORMから。

〜省略
<FORM ACTION="login2.jsp" METHOD="POST" ENCTYPE="application/x-www-form-urlencoded">
省略〜
リスト login2.html

 login.htmlとの違いは、ACTIONの指定先を次に説明するlogin2.jspに変更している点だけです。

〜省略
 4  <jsp:useBean id="loginbean" scope="page" 
class="LoginBean2" />
 
〜省略〜
 
12      if(loginbean.confirm()){
13          session.setAttribute("id",request.getParameter("id"));
14          session.setAttribute("pass",request.getParameter("pass"));
省略〜 
リスト login2.jsp

 login2.jspでは、LoginBean2.classをJavaBeanとして読み込んでいます(4行目)。次に、新しい処理として13、14行目が追加されています。sessionインスタンスにidとpassを記憶させることで、login2.jspの表示終了後も変数の取り出しができるようにしておきます(コラム:セッション管理について参照)。

コラム セッション管理について

 Servlet/JSPならページにまたがる変数をサーバ側に保持させることが可能で、しかもWebブラウザ単位で管理できます。例えば、Webブラウザを一度閉じたのち、もう一度Webブラウザを立ち上げてServlet/JSPにアクセスすると、サーバは各WebブラウザのCookie情報を基にsessionにはめ込まれた変数を返す、といった処理が可能です。しかも、サンプルコードを見れば分かるように、プログラマー側は、

 

変数の取り出し session.getAttribute("名前")

変数のはめ込み session.setAttribute("名前","値")

 

を使い分けるだけです。これもServlet/JSPの有利なところです。

 welcome2.jspリスト14)では、welcome.htmlにJavaコードが追加されています。login.jsp同様、LoginBean2.classのconfirmメソッドを使ってパスワード判定を行い、正しければ正規のwelcomeメッセージを表示します(16〜48行目)。その際、idとpassはsessionインスタンスから取得しています(8、9行目)。

loginbean.setId(session.getAttribute("id").toString());
loginbean.setPass(session.getAttribute("pass").toString());

 これで不正にwelcomeメッセージが見られるのを防ぎ、かつ16〜48行目を書き換えることでほかのページにもユーザー認証機能が付けられます。また、初めてアクセスしてきたWebブラウザの場合は自動的にlogin.htmlを表示し、すでにログインを行ったことがあるWebブラウザの場合は、いちいちパスワード入力を求めずに正規ページを表示することが可能となります。これではやりの「My○○ページ」が作れますね。

 では、実行してみましょう。login2.jsp、login2.html、welcome2.jspリスト14)と使用する画像ファイルを$WEBAPP/ディレクトリに移動します。LoginBean2リスト13)はコンパイルして$WEBAPP/WEB-INF/classesにclassファイルを移動します。

$ $JAVA_HOME/bin/javac LoginBean2.java
$ mv LoginBean2.class $WEBAPP/WEB-INF/classes/

 Webブラウザからhttp://Webサーバ/atmarkit/login2.htmlでLoginページを呼び出し、IDとパスワードを入力して認証開始をクリックしてみましょう。

Java編の終わりに

 Javaは何かと「Beansだ! JINIだ! EJBだ!」と言葉が先行し、これから学んでいこうとする人はつい身構えてしまいがちですが、どんなメソッドを備えればいいかさえ分かってしまえば意外に習得も早いのではないでしょうか。サーバという用途でようやく開花したJavaですが、今後はサーバに限らず、さまざまな場面で見かけることでしょう。そして、プログラムをコンパクトに、また高機能にするためのJDBCはますますは欠かせないものとなるでしょう。

参考:『MySQL徹底入門』(翔泳社)

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。