ビジネスロジックとUIの分離
サーブレットでの実装例ではJavaプログラミング・コードの中に“”といったHTMLタグが書き込まれている。これには次のような欠点がある。
- JavaプログラマーがHTMLレイアウトをしなければならない
- HTMLレイアウトを得意とするアートデザイナーがJavaコードを触らなければならない
- ホームページビルダーのようなHTMLエディタで編集ができない
これらを解決するためにJSP技術があるわけだが、前出のアプリケーションをJSPと連携させることで、JavaコードとHTMLを分離することを試みよう。
まず、プログラムの構造を変えるのだが、ファイル数が多くなるので、設計を整理してからプログラム・コードの説明をする。変更は次の4点である。
- ようこそ画面を表示するJSPを作成する
- ユーザー情報画面を表示するJSPを作成する
- ユーザー情報を保存するBeanを作成する
それぞれのサーブレットでは、データをBeanに保存し、画面を表示するためにJSPを呼び出す。
ここで、次のルールを定める。
Beanは、atmarkit.Userdataとし、プロパティとしてuserid、passwordを持つ。
これをセッション・オブジェクトに『userinfo』という名前で貼り付けることにする
これによって、次のようなプログラム構成になる。
サーブレットとJSPによる構築
現在使われているJSPにはバージョン0.91、0.92、1.0、1.1などがあり、使えるタグが違う。サーバ製品によってサポートしているバージョンにも違いがある。また、JSPを呼び出す方法も、JavaServletのAPIがJSDK 2.1とそれ以前とで違っているので気を付けよう。大まかにいうと、表のようになる。
JSDK 2.0以前 | HttpServiceResponse.callPage() |
---|---|
JSDK 2.1 | RequestDispatcher rd = ServletContext.getRequestDispatcher("JSPname"); rd.forward(request, response); |
JSPの呼び出し方の違い |
さて、入力ページは、先ほどとほとんど同じであり、サーブレットの名前が「atmarkit.Login2」に変わっただけであるので、ソースコードは省略する。
データを保存するためのBeanには、ロジックは基本的に必要ないので、基本的にはプロパティ宣言だけでよいが、あえて行儀の良い形で、Getter、Setterを準備した。
package atmarkit; public class UserinfoBean { private String userid = ""; private String password = ""; public UserinfoBean(String userid, String password) { this.userid = userid; this.password = password; } public String getUserid() { return userid; } public String getPassword() { return password; } public void setUserid(String id) { userid = id; } public void setPassword(String pw) { password = pw; } }
Login2.javaは、次のように書き換えられた。
package atmarkit; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Login2 extends HttpServlet { ServletContext ctx = null; public void init(ServletConfig config) { synchronized(this) { if(ctx == null) { ctx = config.getServletContext(); }}} public void service( HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Webブラウザからの情報の読み取り String userid = request.getParameter("userid"); String password = request.getParameter("password"); // セッション・オブジェクトに保管 HttpSession session = request.getSession(true); UserinfoBean bean = new UserinfoBean(userid, password); session.setAttribute("userinfo", bean); // 画面を表示 RequestDispatcher rd = ctx.getRequestDispatcher("/AtmarkitLogin2.jsp"); rd.forward(request, response); } }
変わったところは、ServletContextのインスタンスをプロパティとして持たせ、初期化ルーチンで受け取っていることと、画面の表示に、RequestDispatcherの取得と、forwardメソッドの呼び出しを行っている点である。つまり、JSDK 2.1レベルでのJSPの呼び出しの手順としては、次の3つが必要である。
(1)ServletContextの取得(initメソッドで行う)
(2)RequestDispatcherの取得(ServletContextインスタンスから)
(3)Forwardメソッドの呼び出し(RequestDispatcherに対して)
これに対して、呼び出されるJSPファイルは、次のようなものになる。
<html> <jsp:useBean id="userinfo" class="atmarkit.UserinfoBean" scope="session"/> <body> <H1><%=userinfo.getUserid() %>さん、ようこそ!</H1> <A HREF='/servlet/atmarkit.Userinfo2'>ユーザー情報</A> </body> </html>
非常に簡単であることが分かってもらえると思う。ここで使用しているJSPのタグは2つであり、<jsp:useBean>と、<%= %>である。
<jsp:useBean>タグは、JavaBeansの変数宣言だと思えばよい。実際、変換されたjavaファイルを見ると、userinfoという名前のオブジェクト参照変数が作成されている。Scope="session"とやることで、セッション・オブジェクトからこのBeanのインスタンスを取ってきてくれる。
<%=タグは、expression(変数式といったりする)である。通常、ここに変数を書き込むと、それが表示されるが、Stringオブジェクトを戻り値とするようなメソッド呼び出しをそのまま書き込むこともできる。ここでの例ではその方式をとっている。これによって、userinfoという名前の変数が指すBeanのインスタンスに対してgetUserid()メソッドの実行結果(つまり、ユーザーID)を表示する、という意味になるのである。
同様に、AtmarkitUserinfo2.java、AtmarkitUserinfo2.jspのソースコードを示す。
package atmarkit; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Userinfo2 extends HttpServlet { ServletContext ctx = null; public void init(ServletConfig config) { synchronized(this) { if(ctx == null) { ctx = config.getServletContext(); }}} public void service( HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Webブラウザに画面(HTML)を送信 // 画面を表示 RequestDispatcher rd = ctx.getRequestDispatcher("/AtmarkitUserinfo2.jsp"); rd.forward(request, response); } }
<HTML> <jsp:useBean id="userinfo" class="atmarkit.UserinfoBean" scope="session"/> <BODY> <H1>パスワードの表示</H1><BR> <TABLE> <TR> <TD>ユーザーID</TD><TD><%=userinfo.getUserid()%></TD> </TR> <TR> <TD>パスワード</TD><TD><%=userinfo.getPassword()%></TD> </TR> </TABLE> </BODY> </HTML
サーブレットのコンテキスト変数と初期化ルーチンは、このままであれば2つのサーブレットで共通なので、スーパークラスを作るというのも1つの手である。
JavaScriptの活用
さらに、もう一つ改造をしよう。もし、入力フィールドに何も入力せずに送信ボタンを押してしまうと、request.getParameter()メソッドの戻り値としてnullが戻る。もちろん、サーブレット側で検査しても構わないが、ネットワーク・トラフィックを抑える目的や、レスポンスを上げるためには、クライアント側で制御できた方がよい。そこで、このような入力フィールドの検査をJavaScriptなどで行うと便利であるので紹介しておく。
最初の入力ページをatmarkit3.htmとして次のように書き換える。
<HTML> <HEAD> <SCRIPT language='JavaScript'> function check() { if(document.forms[0].userid.value == "" | document.forms[0].password.value) { alert('ユーザーIDとパスワードは必ず入力してください'); return false; } return true; } </SCRIPT> <BODY> <FORM action="/servlet/atmarkit.Login2" method="POST"> ユーザーID:<INPUT type="input" name="userid"><BR> パスワード:<INPUT type="password" name="password"><BR> <INPUT type="submit" value="ログイン" onclick='return check()'> </FORM> </BODY> </HTML>
送信ボタンを押した瞬間に「check()」という関数が呼ばれる。これの戻り値を返す指定になっている。trueなら送信するが、falseなら送信しない。関数の中では、useridとpasswordの値を検査して、入力されていなければalert関数(これは組み込み関数)によってダイアログを出し、falseを返すことにより送信をやめる。実際に何も入力せずに送信ボタンを押すと、次のようなメッセージ・ボックスが表示される。
JSPファイルの編集
ソースコードを見れば、Bean、サーブレットのファイルにはJavaのコードが、HTML、JSPにはHTMLのタグとJSPのタグしか記述されていないことが分かっていただけると思うが、さらにその恩恵を実感してもらうために、WYSIWYGエディタでの編集をご紹介しよう。
WebSphereファミリーの「WebSphere Studio V4.0」は、Web開発ツールのセットである。この中に含まれている「PageDesigner」は、ホームページビルダーにBeanなどのJSPタグの機能を追加したものである。PageDesingerで先ほどのAtmarkitLogin2.jspを開くと、次のような形で表示される。
ツールバーをほとんど隠してしまっているので寂しいウィンドウであるが、ホームページビルダーで提供している機能はすべて利用可能である。もちろん、このウィンドウ上で絵を貼り付けたり、色を変えたりするなどの作業はすべてWYSIWYG操作で編集可能である。このような機能によって、色彩感覚の優れたデザイナーが、Webページを使ったアプリケーション開発に、「デザイナーとして」参加することが可能なのである。
今回は、サーブレットとJSPの連携について、実例を使って実装方法を解説した。次回の後編では、このBeanの後方で、EJBを使ってRDB上のデータを利用する方法を解説する予定である。
筆者紹介
米持幸寿
1987年、日本アイ・ビー・エム入社。
IBMメインフレームOSであるVSE、およびVM関連ソフトウェアプロダクト の保守、 システム無人化ソフトウェア開発を手がける。現在はJava、XML、EJBに関わるプロモーション活動を行っている。
Copyright © ITmedia, Inc. All Rights Reserved.