連載
» 2001年11月09日 00時00分 UPDATE

Tomcatを使う「JSPプログラミング」(11):データベースを活用したアプリケーション

[三谷純,タイムインターメディア]

前回は、JSPからデータベースにアクセスする方法を紹介しました。今回は、より具体的な例として、実際にJSPとデータベースを連携させた簡単なWebアプリケーションを作成してみます。例として取り上げるWebアプリケーションは、オンラインで出欠の登録と確認を行うことができる、出欠表アプリケーションです。データベースへのアクセスを行う基本的な部分は、前回紹介した方法を使用しています。


出欠登録アプリケーションを作成してみる

 Webアプリケーションを作成する作業の流れを理解するために、いつもとは説明の順番を変えて、今回作成する出欠表アプリケーションを最初に見てみましょう。

 何も登録されていない状態では、次のように各メンバーに個別の出欠登録フォームが表示されます。それぞれのメンバーが、自分の欄のフォームで出席と欠席のどちらかを選択し、コメント文を入力して「登録」を行います。

出欠登録フォーム 出欠登録フォーム

 入力された内容はデータベースに格納され、その内容が次のように表示されます。出席するメンバーと欠席するメンバーが確認でき、未定のメンバーについては、引き続き登録用フォームが表示されます。

出欠が未定のメンバーのみ、登録フォームが表示される 出欠が未定のメンバーのみ、登録フォームが表示される

 それでは、このような出欠の登録と確認を行うためのWebアプリケーションを作成していきましょう。

テーブルを作成(変更)する

 今回は、データを格納するテーブルとして、前回作成したmemberテーブルを再利用することにします。今回のWebアプリケーションの機能である出欠を取るに当たり、それぞれのメンバーについて、出欠状態とコメントの情報を格納するカラムを新しく追加する必要があります。それぞれ、整数型で表される出欠状態と、テキスト型で表されるコメントのカラムをテーブルに追加することにします。

 PostgreSQLでは、次のようにしてテーブルにカラムを追加できます。

alter table member add column attendance integer;
alter table member add column comment text;

 テーブルの様子は、

\d テーブル名

と入力することで確認できます。ここで、memberテーブルを確認してみると、次のように表示されます。

\d member
                                        Table "member"
 Attribute  |         Type          |                         Modifier
------------+-----------------------+----------------------------------------
 member_id  | integer               | not null default nextval…(略)*1
 name       | character varying(32) | not null
 kana       | character varying(32) | not null
 attendance | integer               |
 comment    | text                  |
        Index: member_pkey
*1:('"member_member_id_seq"'::text) を省略

 出欠状態を格納するattendanceカラムと、コメントを格納するcommentカラムが新たに追加されたことが確認できます。

一覧表示用のJSPページを作成する

 それでは早速、一覧表示用のJSPページを作成しましょう。データベースへのアクセスには、前回に紹介した、MyDBAccessクラスをそのまま使用することにします。プログラムコードは次のようになります。

・11-1.jsp
 1: <%@ page import="java.sql.*, atmarkit.MyDBAccess"
 2: contentType="text/html; charset=euc-jp" %>
 3: <%
 4: // 内容: データベースにアクセスする
 5: 
 6: // MyDBAccess のインスタンスを生成する
 7: MyDBAccess db = new MyDBAccess();
 8: 
 9: // データベースへのアクセス
10: db.open();
11: 
12: // メンバーの情報を取得
13: ResultSet rs = db.getResultSet("select * from member order by member_id");
14: 
15: // 一覧表示用のテーブル
16: String tableHTML = "<table border=1>";
17: tableHTML += "<tr bgcolor=\"000080\"><td><font color=\"white\">ID</font></td>"
18:           + "<td nowrap><font color=\"white\">名前</font></td>"
19:           + "<td colspan=2><font color=\"white\">出欠</font></td>";
20: 
21: // 取得された各結果に対しての処理
22: while(rs.next()) {
23: 
24:     int id = rs.getInt("member_id"); // メンバーIDを取得
25:     String name = rs.getString("name"); // メンバー名を取得
26:     int state = rs.getInt("attendance"); // 出欠状態を取得
27:     String comment = rs.getString("comment"); // コメント文を取得
28: 
29:     // 文字コードの変換
30:     name = new String(name.getBytes("8859_1"), "EUC_JP");
31:     if(comment != null){
32:         comment = new String(comment.getBytes("8859_1"), "EUC_JP");
33:     }
34: 
35:     String cell1;
36:     String cell2;
37:     switch(state) {
38:     case -1: // 欠席の場合
39:         cell1 = "<font color=\"red\"><b>欠席</b></font>";
40:         cell2 = "<br>" + comment + "<br><br>";
41:         break;
42: 
43:     case 1: // 出席の場合
44:         cell1 = "<font color=\"blue\"><b>出席</b></font>";
45:         cell2 = "<br>" + comment + "<br><br>";
46:         break;
47: 
48:     default: // 未定の場合
49:         cell1 = "<b>未定</b>";
50:         cell2 = "<form action=\"11-2.jsp\">"
51:             + "<input type=\"hidden\" name=\"member_id\" value=\"" + id + "\">"
52:             + "<input type=\"radio\" value=\"1\" checked name=\"attendance\">出席"
53:             + "<input type=\"radio\" value=\"-1\" name=\"attendance\">欠席<br>"
54:             + "<input type=\"text\" name=\"comment\" size=36> "
55:             + "<input type=\"submit\" value=\"登録\"></form>";
56:     }
57: 
58:     // テーブル用HTMLを作成
59:     tableHTML += "<tr><td align=\"right\" bgcolor=\"A0A0A0\"><b>" + id + "</b></td>"
60:         + "<td nowrap>" + name + "</td><td>" + cell1 + "</td><td>"
61:         + cell2 + "</td></tr>";
62: }
63: 
64: tableHTML += "</table>";
65: 
66: // データベースへのコネクションを閉じる
67: db.close();
68: 
69: %>
70: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
71: <html>
72: <head><title>データベースへのアクセス</title></head>
73: <body>
74: <p>-- データベースへのアクセス --</p>
75: <p>
76: <b>JSP勉強会 出欠状況一覧</b><br>
77: <%= tableHTML %>
78: </p>
79: </body>
80: </html>

 今回は、メンバーIDの順にそれぞれのメンバーの情報を取得するために、

select * from member order by member_id

というSQL文を使用します。このSQL文の実行結果の取得は6〜13行目の一連の手続きで行えます。この処理は、前回紹介した方法をそのまま使用しています。

 6: // MyDBAccess のインスタンスを生成する
 7: MyDBAccess db = new MyDBAccess();
 8: 
 9: // データベースへのアクセス
10: db.open();
11: 
12: // メンバーの情報を取得
13: ResultSet rs = db.getResultSet("select * from member order by member_id");

 SQL文を実行して取得したResultSetに対して、22〜62行目のwhileループで順に処理を行っています。

 出欠状態は、attendanceカラムの値によって、次のように定めました。

attendance カラムの値 出欠状態
1 出席
-1 欠席
1, -1 以外の値 未定

 出席、欠席のいずれかが決まっている場合は、その状態とコメント文を表示し、未定の場合は、登録用のフォームを表示するようにしています。この表示内容の振り分けは、37〜56行目のswitch文で行っています。

 最後に67行目でデータベースのコネクションを閉じています。

66: // データベースへのコネクションを閉じる
67: db.close();

以上のプログラムで、出欠の状態を表示できるようになりました。

 次に、登録内容をデータベースに格納するためのプログラム11-2.jspを作成します。

データベースの更新

 11-1.jspの登録フォームから入力された値をデータベースに登録するためのJSPプログラム、11-2.jspを作成します。コードは次のようになります。

 1: <%@ page import="java.sql.*, atmarkit.MyDBAccess"
 2: contentType="text/html; charset=euc-jp" %>
 3: <%
 4: // 内容: データベースにアクセスする
 5: 
 6: // 入力された引数を取得する
 7: String comment = request.getParameter("comment");
 8: String attendance = request.getParameter("attendance");
 9: String member_id = request.getParameter("member_id");
10: 
11: // MyDBAccess のインスタンスを生成する
12: MyDBAccess db = new MyDBAccess();
13: 
14: // データベースへのアクセス
15: db.open();
16: 
17: // データベース更新用のSQL文を作成
18: String sql = "update member set comment='" + comment
19:            + "', attendance=" + attendance
20:            + " where member_id=" + member_id;
21: 
22: // SQL文を実行
23: db.execute(sql);
24: 
25: // データベースへのコネクションを閉じる
26: db.close();
27: 
28: // 元のページへリダイレクト
29: response.sendRedirect("11-1.jsp");
30: %>

 まず初めに、11-1.jspから入力されたパラメータ値を7〜9行目で取得します。ここでは、コメント文、出欠状態、メンバーIDを取得しています。

 その後、データベースへのアクセスを行うための処理を行います。これは前節のものと同じ手順になります。さて、ここでのデータベースの更新は、次のようなSQL文で行います。

update member set comment='コメント文', attendance=出欠状態コード where member_id=メンバーID

 上記のSQL文によって、特定のメンバーIDを持つメンバーの、コメント文、出欠状態のデータを更新することができます。

 さて、このJSPプログラムでは、HTML文の表示は行わず、データベースの更新のみを行います。処理が終わった時点で、元のページへのリダイレクトを29行目で行っています。データが更新された後、元のJSPページを再表示することになります。

28: // 元のページへリダイレクト
29: response.sendRedirect("11-1.jsp");

以上で、出欠表アプリケーションが完成です。細かい点にはあまりこだわらず、基本的な処理のみで実現しましたので、それほど難しい点はないでしょう。

セキュリティについて

 本連載の第10回第11回では、JSPからデータベースを扱う方法を紹介しましたが、ここで紹介しているプログラムコードは基本的なデータベースの扱い方を説明するもので、特にセキュリティに関する配慮は行っていないことに注意してください。実際に不特定多数のユーザがアクセスするプログラムを作る場合には、JSP内部でSQL文を生成する箇所で、セキュリティホールを作ってしまわないか、十分に気を配る必要があります。具体的には、SQL文の生成にrequestオブジェクト内のパラメータの値を使用する場合には、そのパラメータの値によって危険なSQL文が生成されてしまうことのないよう、チェックを行う仕組みが必要になります。

改良のヒント

 さて、今回は出欠の登録と確認を行える簡単なWebアプリケーションを作成しました。数人の身内で使うものとしては、この程度で大丈夫かもしれませんが、今後の拡張性や安定性、頑丈性を考えると、まだまだ不十分な点がたくさんあります。より完成度を高めるためには、さらに多くのことを考慮する必要がありますが、すべての詳細を記し尽くすことはできませんので、今後の改良のヒントを以下に挙げて、まとめさせていただきます。

  • テーブルの設計
     今回は、既存のmemberテーブルにカラムを追加して対応する、という少々乱暴な方法を取りました。今後、複数のイベントを管理する必要が出てきた場合、この方法では対応が困難になってきます。今後の拡張を考慮するのであれば、新しくイベント用のテーブルを作るなどして対応した方がよいでしょう。

  • エラー処理
     今回のプログラムでは、エラーチェックを含めていません。すべてが順調に処理されればよいのですが、データベースがダウンしていたり、うまく接続できなかったりすることがあります。そのような場合には処理を中断して適切なエラーメッセージを表示するための工夫が必要になります。

  • 入力された文字列の処理
     今回は、入力されたコメント文をそのままデータベースに格納し、そのままHTML文に出力しました。しかし、データベースに格納する際にエスケープしなければならない文字「'」や、HTML文で表示するに当たってエスケープしなければならない文字「>」「<」「&」などがあります。実際には、これらを適切なエスケープ文字に置き換える処理が必要になります。また、入力文字数の制限なども考慮する必要があるでしょう。

  • アクセス制限
     出欠表には個人名などが表示されるので、不特定多数の人には公開したくない場合が多いでしょう。そのような場合に、パスワードによるアクセス制限などが必要になります。

  • 個人認証
     今回の例では、メンバーの良心に頼っていましたが、AさんがBさんの出欠を勝手に入力することができてしまいます。これを防ぐために、パスワードなどによる個人認証の仕組みを追加する必要があります。

  • 修正機能
     今回の例では、一度登録された内容を修正できません。どうしても必要であれば、データベースを直接操作することになります。この修正作業をWeb上で行えるようにするためには、それ用のページを新たに作る必要があるでしょう。

  • パフォーマンス
     今回の例では、データベースへのアクセスがそれほど頻繁に起こるとは思えませんが、数千、数万のコネクションが発生するようなWebアプリケーションでは、毎回データベースへのコネクションを張るのは、あまり効率的ではありません。大規模なWebアプリケーションでは、コネクションをプールするような仕組みも必要になってきます。

  • 異なるクライアントへの対応
     今回は、PC上のWebブラウザのみを対象にしました。携帯電話からもアクセスできるようにするには、クライアントのUserAgentによる振り分け処理などの工夫が必要になります。

 以上、より本格的なWebアプリケーションを作るための改良点のヒントを挙げてみました。不特定多数の人からアクセスを受けることを想定したWebアプリケーションを作成するには、上記のように、さまざまなことを考慮する必要があります。実際のアプリケーションでは、エラー処理と文字列処理、セキュリティのための仕組みがコードの大半を占めるようになってしまうことが多いでしょう。よりよいサービスを提供するために、これらの労力を惜しまず、頑張りましょう。

 さて、いままで続いてきたこの連載も、いよいよ今回で終了です。JSPとはどのようなものか、という説明からデータベースを用いる方法まで、計11回にわたり、長い間お付き合いいただきまして、本当にありがとうございました。

 これからJSPを活用なさる皆さんにとって、本連載が少しでもお役に立ちましたならば幸いです。

追記:セキュリティについて

本連載ではJSPを用いて初めてデータベースを扱う方を対象とし、基本的な使用法の紹介を行っています。そのため、特にセキュリティホールに関する対策はなされていません。ここで紹介されているプログラムをそのままセキュリティを意識すべきアプリケーションの開発には用いないようにご注意ください。特にユーザーからの入力を受け取ってSQL文を生成する際には、危険なSQL文が生成されないように注意する必要があります。入力のチェックについては「JSPコーディング・テクニック 第3回」の説明をご覧ください。


著者プロフィール

三谷純

タイムインターメディア


Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

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

メールマガジン登録

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