SOAフレームワークBeehiveに挑戦(3) 4/4

PollinateでNetUI Page Flowプログラミング

www.netpotlet.com
原田洋子
2005/7/1

データ表示方法とバリデーション

 ひととおりのプログラミングができましたので、もう少しいろいろな機能を使ってみましょう。

登録フォーム

 今度は図15のような登録フォームを作ってみます。このフォームにはテキストボックスのほか、オプションからの選択、テキストエリアがあります。フォームの読み込みという点ではログインフォームと同じで、JavaBeansのプロパティが増えた程度の違いしかありません。ここでは、selectタグの中で使うoptionタグの表示方法と入力値のバリデーションを中心に見ていきます。

図15 登録ページ(画面をクリックすると拡大します)

登録フォームのフロー

 プログラムの前に登録処理がどのようなフローになっているかから見ていきましょう。図16がプログラミングが完成した後のフロー図です。beginアクション実行結果による分岐はなく、すべてindex.jspにフォワードされますが、わざわざbeginアクションを用意したのはoptionタグで表示するパラメータ受け渡しのためです。登録フォームのindex.jspはprocessSignupアクションにポストします。processSignupでは入力された値が適当であるかどうかのバリデーションを行い、適当と判断されsignup_successが返されると、先ほどのログインフォームlogin.jspにフォワードし、不適当と判断されるとsignup_failureが返されてfail.jspにフォワードします。fail.jspにはbeginアクションへのリンクがあるので、再トライする場合はリンクをクリックしてbeginアクションから再スタートします。

図16 登録処理のフロー図(画面をクリックすると拡大します)

登録フォームのコントローラ

 登録フォームのコントローラはリスト6のようになっています。optionタグ表示に必要なパラメータを作っているところです。questionMapは注釈の22〜26行目で出力があることを記述し、30〜34行目のbegin()メソッドでforwardオブジェクトのaddActionOutput()メソッドを実行して、JSPからquestionMapの名前でオブジェクトを参照できるようにしてあります。これがJSPページにデータを渡す1つの方法です。

 processSignup()メソッドには、フォワードのほかにバリデーションを行う注釈(41〜57行目)が付いています。このバリデーションではメールアドレスが妥当であること(42〜46行目)、ユーザー名が4文字以上あること(47〜51行目)、パスワードが6文字以上あること(52〜56行目)を検証しています。さらに、検証の結果が正しくない場合にはfail.jspにフォワードする注釈(58〜61行目)もあります。検証する対象は76〜131行目で定義しているJavaBeans、SignupFormのプロパティを指定しています。Apache Beehiveが提供しているバリデータにはメールアドレス、文字列の最短/最長、日付、クレジットカード番号などがあります。また、自分でバリデータを定義できるようにもなっています。

  1 package signup;
  2 
  3 import java.util.HashMap;
  4 
  5 import org.apache.beehive.netui.pageflow.Forward;
  6 import org.apache.beehive.netui.pageflow.PageFlowController;
  7 import org.apache.beehive.netui.pageflow.annotations.Jpf;
  8 
  9 @Jpf.Controller
 10 public class Controller extends PageFlowController {
 11     public HashMap questionMap = new HashMap();
 12 
 13     protected void onCreate() {
 14         questionMap.put("vacation", "旅にでるなら…");
 15         questionMap.put("color", "色なら…");
 16         questionMap.put("music", "音楽なら…");
 17     }
 18 
 19     @Jpf.Action(
 20         forwards={
 21             @Jpf.Forward(name="signup",
                             path="/signup/index.jsp",
 22                 actionOutputs = {
 23                     @Jpf.ActionOutput(
                            name="questionMap",
 24                         type=java.util.HashMap.class,
 25                         required=true)
 26                 }
 27             )
 28         }
 29     )
 30     public Forward begin() {
 31         Forward forward = new Forward("signup");
 32         forward.addActionOutput("questionMap",
                                    questionMap);
 33         return forward;
 34     }
 35 
 36     @Jpf.Action(
 37         forwards={
 38             @Jpf.Forward(name="signup_success",
                             path="/login.jsp"),
 39             @Jpf.Forward(name="signup_failure",
                             path="fail.jsp")
 40         },
 41         validatableProperties={
 42             @Jpf.ValidatableProperty(
 43                 propertyName="email",
 44                 validateRequired=@Jpf.ValidateRequired(),
 45                 validateEmail=@Jpf.ValidateEmail()
 46             ),
 47             @Jpf.ValidatableProperty(
 48                 propertyName="username",
 49                 validateRequired=@Jpf.ValidateRequired(),
 50                 validateMinLength=@Jpf.ValidateMinLength(
                        chars = 4)
 51             ),
 52             @Jpf.ValidatableProperty(
 53                 propertyName="password",
 54                 validateRequired=@Jpf.ValidateRequired(),
 55                 validateMinLength=@Jpf.ValidateMinLength(
                        chars = 6)
 56             )
 57         },
 58         validationErrorForward=
 59             @Jpf.Forward(
 60                 name="signup_failure", path="fail.jsp"
 61             )
 62     )
 63     public Forward processSignup(SignupForm form) {
 64         String email = form.getEmail();
 65         String username = form.getUsername();
 66         String password = form.getPassword();
 67         String confirm = form.getConfirm();
 68         String question = form.getQuestion();
 69         String answer = form.getAnswer();
 70         if ((confirm != null) &&
                (!password.equals(confirm))) {
 71             return new Forward("signup_failure");
 72         }
 73         return new Forward("signup_success");
 74     }
 75 
 76     public static class SignupForm {
 77         private String email;
 78         private String username;
 79         private String password;
 80         private String confirm;
 81         private String question;
 82         private String answer;
 83 
 84         public String getAnswer() {
 85             return answer;
 86         }
 87 
 88         public void setAnswer(String answer) {
 89             this.answer = answer;
 90         }
 91 
 92         public String getConfirm() {
 93             return confirm;
 94         }
 95 
 96         public void setConfirm(String confirm) {
 97             this.confirm = confirm;
 98         }
 99 
100         public String getEmail() {
101             return email;
102         }
103 
104         public void setEmail(String email) {
105             this.email = email;
106         }
107 
108         public String getPassword() {
109             return password;
110         }
111 
112         public void setPassword(String password) {
113             this.password = password;
114         }
115 
116         public String getQuestion() {
117             return question;
118         }
119 
120         public void setQuestion(String question) {
121             this.question = question;
122         }
123 
124         public String getUsername() {
125             return username;
126         }
127 
128         public void setUsername(String username) {
129             this.username = username;
130         }
131     }
132 }
リスト6 WebContent/signupディレクトリのController.java

登録フォームのJSP

 登録フォームのJSPはリスト7のようになっています。このJSPにはオプション選択のためのPage Flowタグ(33〜35行目)があるのと、HTMLのtextareaタグを出力するPage Flowタグ(39行目)があることがログインフォームと違うところです。バリデーションするかどうかについてはJSPには何も現れません。さて、コントローラでquestionMapの名前で参照できるようにセットしたパラメータですが、34行目で

        optionsDataSource="${pageInput.questionMap}"

のように使っています。これだけで次のようなHTMLが作られ、図15に示すオプションが表示されます。

<input type="hidden"
       name="wlw-select_key:{actionForm.question}OldValue"
       value="true">
<select name="wlw-select_key:{actionForm.question}" size="1">
  <option value="color">色なら…</option>
  <option value="vacation">旅にでるなら…</option>
  <option value="music">音楽なら…</option>
</select>

 この方法はjava.util.Map型以外にjava.lang.String型の配列にも対応しています。詳細は<netui:select>タグのドキュメントを参照してください。

 このようにMap型や配列型を繰り返し表示する方法は、netui-dataをプレフィックスにする<netui-data:dataGrid>や<netui-data:repeater>といったPage Flowタグライブラリにもあります。テーブルを作る場合に便利なタグで、java.sql.ResultSetやjavax.sql.RowSet型のオブジェクトにも適用できます。

 リスト8はバリデーションの結果、適当ではないと判断された場合に表示されるfail.jspです。

 1 <%@ page contentType="text/html; charset=euc-jp"%>
 2 <%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0"
 3            prefix="netui" %>
 4 <netui:html>
 5   <head>
 6     <title>ユーザ登録</title>
 7     <netui:base/>
 8     <link rel="stylesheet"
         href="${pageContext.request.contextPath}/site/default.css"
 9       type="text/css"/>
10   </head>
11   <netui:body>
12     <p>・※・ 登録してください ・※・</p>
13       <netui:form action="processSignup">
14         <table>
15           <tr>
16             <td class="tag">メールアドレス</td>
17             <td><netui:textBox dataSource="actionForm.email"/>
               </td>
18           </tr>
19           <tr>
20             <td class="tag">ユーザ名</td>
21             <td><netui:textBox dataSource="actionForm.username"/>
               </td>
22           </tr>
23           <tr>
24             <td class="tag">パスワード</td>
25             <td><netui:textBox dataSource="actionForm.password"
                                  password="true"/></td>
26           </tr>
27           <tr>
28             <td class="tag">パスワード(確認)</td>
29             <td><netui:textBox dataSource="actionForm.confirm"
                                  password="true"/></td>
30           </tr>
31           <tr>
32             <td class="tag">質問</td>
33             <td><netui:select dataSource="actionForm.question"
34                   optionsDataSource="${pageInput.questionMap}"
35          size="1"/></td>
36           </tr>
37           <tr>
38             <td class="tag">答え</td>
39             <td><netui:textArea dataSource="actionForm.answer"/>
               </td>
40           </tr>
41           <tr>
42             <td colspan="2" class="tag">
                 <netui:button value="登録" type="submit"/></td>
43           </tr>
44         </table>
45       </netui:form>
46   </netui:body>
47 </netui:html>
リスト7 WebContent/signupディレクトリのindex.jsp

 1 <%@ page contentType="text/html; charset=euc-jp"%>
 2 <%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0"
 3            prefix="netui" %>
 4 <netui:html>
 5   <head>
 6     <title>ユーザ登録失敗</title>
 7     <netui:base/>
 8   </head>
 9   <netui:body>
10     <p>ユーザ登録できませんでした。</p>
11     <p><netui:anchor action="begin">》登録にチャレンジ
          </netui:anchor></p>
12   </netui:body>
13 </netui:html>
リスト8 WebContent/signupディレクトリのfail.jsp

エラーメッセージの表示

 Apache Beehiveにはバリデーションの結果、何が駄目だったかを表示する機能があります。この機能を利用するには例えばfail.jspに、

      <netui:error key="email"/><br/>
      <netui:error key="username"/><br/>
      <netui:error key="password"/><br/>

のようにエラーメッセージの表示場所を用意しておきます。コントローラには

41 validatableProperties={
42     @Jpf.ValidatableProperty(
43         propertyName="email", displayName="Email address",
44         validateRequired=@Jpf.ValidateRequired(),
45         validateEmail=@Jpf.ValidateEmail()
46     ),
47     @Jpf.ValidatableProperty(
48         propertyName="username",displayName="Username",
49         validateRequired=@Jpf.ValidateRequired(),
50         validateMinLength=@Jpf.ValidateMinLength(chars = 4)
51     ),
52     @Jpf.ValidatableProperty(
53         propertyName="password", displayName="Password",
54         validateRequired=@Jpf.ValidateRequired(),
55         validateMinLength=@Jpf.ValidateMinLength(chars = 6)
56     )
57 },

のように、各プロパティをバリデーションする注釈にdisplayNameを追加し、デフォルトメッセージの前に付ける文字列を指定します。

 このようにして、メールアドレスにaaa、ユーザー名にa、パスワードが空欄のまま登録ボタンをクリックすると図17のようにエラーメッセージが表示されます。ただし、PollinateのApache Beehiveはバージョンが古いためか、JSPのタグを<netui:error value="email"/>のようにkeyではなく、valueにしないと動きません。いずれ、最新版のBeehiveに対応するでしょう。

 なお、表示されるメッセージを変える方法や日本語のメッセージを表示する方法はhttp://incubator.apache.org/beehive/の左側にあるナビゲーションを

 Documentation → Page Flows → Validation

とたどったところに詳細なドキュメントがありますので参照してください。

図17 バリデーションエラーの表示(画面をクリックすると拡大します)

まとめ&サンプルコードのダウンロード

 3回にわたってApache BeehiveとEclipseプラグインのPollinateを紹介してきましたが、いかがだったでしょうか? Beehiveは第1回ではα版がリリースされたばかりでしたが、いまでは1.0 Milestone 1という正式リリースも間近というバージョンがリリースされています。ドキュメントも充実してきてより使いやすくなってきました。

 今回紹介したPage FlowsはWebアプリケーションフレームワークですから、ほかにも多数の類似製品がある分野です。メタデータ(注釈)を利用したEoDがどのくらいほかのフレームワークと違うのかを比べやすいところでもありますから、ぜひ試してみてください。メタデータの勉強にもなるはずです。

 Webアプリケーションフレームワークの世界ではJSF(JavaServer Faces)という標準仕様が決まってさほど時間はたっていませんが、対応した、あるいは対応を表明するフレームワークがぞくぞくと増えています。Apache Beehiveも例外ではありません。今後、JSF対応を進めるうえで、JSFタグとPage Flowタグをどのように共存させていくのかなどの問題で、Beehiveが変わっていく可能性は考えられるでしょう。しかし、Beehiveはオープンソース製品ですから、育てていこうというくらいのつもりで使ってみるといいのではないでしょうか。ユーザーが増えるにつれ、製品の完成度も上がっていくでしょう。

 本連載は今回で終わりです。ご愛読ありがとうございました。(連載完)

4/4

 Index
SOAフレームワークBeehiveに挑戦(3)
PollinateでNetUI Page Flowプログラミング
  Page 1
・NetUI Page Flowの概要
・プログラミング環境
・プログラミングのためのドキュメント
  Page 2
・シンプルなプログラム
 −コントローラのプログラミング
  Page 3
 −JSPページのプログラミング
 −サーバのセットアップと実行
Page 4
・データ表示方法とバリデーション
・まとめ&サンプルコードのダウンロード


「SOAフレームワークBeehiveに挑戦」


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間