ビジネスロジックと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にはバージョン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の呼び出し方の違い |
サーブレットとJSPによる構築
今回は、WebSphereV3.5を前提にするために、JSDK2.1+JSP1.0の組み合わせで解説する。
さて、入力ページはほとんど変更がない。サーブレットの名前が「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 { // ブラウザからの情報の読み取り String userid = request.getParameter("userid"); String password = request.getParameter("password"); // セッションオブジェクトに保管 HttpSession session = request.getSession(true); UserinfoBean bean = new UserinfoBean(userid, password); session.putValue("userinfo", bean); // 画面を表示 RequestDispatcher rd = ctx.getRequestDispatcher("/AtmarkitLogin2.jsp"); rd.forward(request, response); } }
変わったところは、ServletContextのインスタンスをプロパティとして持たせ、初期化ルーチンで受け取っていることと、画面の表示にRequestDispatcherの取得と、forwardメソッドの呼び出しを行っている点である。つまり、JSDK 2.1レベルでのJSPの呼び出しの手順としては、次の3つが必要である。
- ServletContextの取得(initメソッドで行う)
- RequestDispatcherの取得(ServletContextインスタンスから)
- 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)を表示する、という意味になるのである。
同様に、Userinfo2.java、Atmarkituserinf2.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 { // ブラウザに画面(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つの手である。
WebSphereの場合は、以下の場所にサーブレットに変換されたJSPのコードとクラスファイルが入っているので見てみよう。
C:\WebSphere\AppServer\temp\default_host\default_app
JavaScriptの活用
ここで、もう1つだけ改造をしよう。もし、入力フィールドに何も入力せずに送信ボタンを押してしまうと、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のタグしか記述されていないことがわかっていただけた思う。つまりは、ビジネスロジックとUIの分離されているわけだ。だが、さらにその恩恵を実感してもらうために、WYSIWYGエディタでの編集をご紹介しよう。
WebSphereファミリーの「WebSphere Studio V3.5」は、Web開発ツールを集めたスイート製品である。この中に含まれている「PageDesigner」は、ホームページビルダーにBaenなどのJSPタグの機能を追加したものである。PageDesingerで先程のAtmarkitLogin2.jspを開くと、次のような形で表示される。
ツールバーをほとんど隠してしまっているのでさみしいウィンドウであるが、ホームページビルダーで提供している機能はすべて利用可能である。もちろん、このウィンドウ上で絵を貼り付けたり、色を変えるなどの作業はすべてWYSIWYGで編集可能である。このような機能によって、色彩感覚の優れたデザイナが、ウェブページを使ったアプリケーション開発に、「デザイナとして」参加することが可能なわけだ。
今回は、サーブレットとJSPの連携について、実例を使って実装方法を解説した。次回の後編では、このBeanの後方で、Enterprise JavaBeanを使ってRDB上のデータを利用する方法を解説する予定である。
筆者紹介
米持幸寿
1987年、日本アイ・ビー・エム入社。
IBMメインフレームOSであるVSE、およびVM関連ソフトウェアプロダクト の保守、 システム無人化ソフトウェア開発を手がける。現在はJava、XML、EJBに関わるプロモーション活動を行っている。
Copyright © ITmedia, Inc. All Rights Reserved.