連載
» 2004年06月26日 00時00分 公開

Validatorによる妥当性検証の実現(後編)Strutsを使うWebアプリケーション構築術(6)(2/2 ページ)

[山田祥寛,@IT]
前のページへ 1|2       

JSPファイルのValidator対応

 Validatorプラグインのクライアントサイドの検証機能とサーバサイドの検証機能の両方を有効にするには、JSPファイルも変更を行う必要があります。以下は、第4回「リクエスト情報を制御するアクションフォームBeans」で紹介したBookUpdate.jspの変更部分を示したものです(赤字部分)。

BookUpdate.jsp(第4回からの差分)
<%@ page contentType="text/html;charset=Windows-31J" %>
<%@ taglib uri="/tags/struts-html"  prefix="html" %>
<%@ taglib uri="/tags/struts-logic" prefix="logic" %>
<html:html>
<head>
<title>書籍情報更新・削除</title>
</head>
<body>
<h1 style="color:white;background-color:#525D76;">書籍情報更新・削除</h1>
<html:javascript formName="BookUpdateForm" />
<html:form action="/BookWriteAction"
  onsubmit="return validateBookUpdateForm(this)">
<table border="0">
  ...中略...
  <tr>
    <td colspan="2">
      <html:submit property="submit" value="保存" />
      <html:reset  property="reset"  value="取消" />
    </td>
  </tr>
</table>
</html:form>
<html:errors />
</body>
</html:html>

■クライアントサイドの検証機能を有効化

 クライアントサイドの検証機能を有効化するのは、html:javascript要素とhtml:form要素の役割です。この2行によって、クライアント側で検証を行うためのJavaScriptが出力されます。

<html:javascript formName="アクションフォームBeansの論理名" />
<html:form action="..."
  onsubmit="return validate[アクションフォームBeansの論理名](this)">

 クライアント側の検証機能が有効になっているかどうかは、コンテキストメニューの[ソースの表示]などで表示されるHTMLコードで確認することができます。HTMLコード内に、以下のようなscriptタグが出力されていれば成功です。

<script type="text/javascript" language="Javascript1.1"> 
<!-- Begin 
  ...中略...
//End -->
</script>

 クライアントサイドの検証結果(エラーメッセージ)は、ダイアログボックスで表示されます。

■サーバサイドの検証機能を有効化

 サーバサイドの検証結果を出力するのは、html:errors要素の役割です。この1行を記述しておくことで、サーバサイドで発生したエラーメッセージが、html:errors要素の部分に表示されます。

 ただし、サーバサイドの検証機能は、クライアントサイドの検証機能と異なり、アクションフォームBeans、struts-config.xmlがともに正しく設定されていないと、正常に動作しませんので、注意してください。

データ登録・更新を行うアクションクラスの定義

 最後に、検証処理を通過した入力データを処理するアクションクラス「BookUpdateProcess」です。ここでは、検証のための記述は特に必要ありません。これは、従来のアプリケーションではビジネスロジック中に記述せざるを得なかった検証処理を、Validatorプラグインでは完全に独立させているからです。これは、コードの保守性、可搬性などの面からも極めて重要なポイントで、Validatorプラグイン(あるいはStruts)の利点といえます。

BookUpdateProcess.java
package struts;

import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.*;
import org.apache.struts.action.*;

public final class BookUpdateProcess extends Action {
  public ActionForward execute (ActionMapping map, ActionForm fm,
HttpServletRequest request, HttpServletResponse response) {
     // アクションフォームBeansクラスを取得
    BookUpdateForm objFrm=(BookUpdateForm)fm;
     // BookInfoクラスを介して、入力データをデータベースに登録(更新)
    BookInfo objBok=new BookInfo();
    objBok.setIsbn(objFrm.getIsbn());
    objBok.setTitle(objFrm.getTitle());
    objBok.setAuthor(objFrm.getAuthor());
    objBok.setPrice(objFrm.getPrice());
    objBok.setPublish(objFrm.getPublish());
    objBok.setPublished(objFrm.getPublished());
    objBok.updateBookInfo();
    return map.findForward("success");
  }
}

 次は、JavaBeansクラスのBookInfoの修正点を以下に示します。

BookInfo.java(第4回からの差分のみ)
package struts;

import java.io.*;
import java.sql.*;
import java.util.*;
import java.text.*;
import javax.sql.*;
import javax.naming.*;

public final class BookInfo implements Serializable {
  ...中略...
  public void updateBookInfo() {
    Connection db=null;
    PreparedStatement objPs1=null;
    PreparedStatement objPs2=null;
    try {
      Context ctx=new InitialContext();
      DataSource ds=(DataSource)ctx.lookup("java:comp/env/jdbc/Struts");
      db=ds.getConnection();
      objPs1=db.prepareStatement("SELECT * FROM bok_inf_tbl WHERE isbn=?");
      objPs1.setString(1,this.isbn);
      ResultSet rs=objPs1.executeQuery();
       /* ISBNコードをキーにテーブル内を検索し、データが存在する
        * 場合は更新処理を、存在しない場合は登録処理を行います */
      if(rs.next()){
        objPs2=db.prepareStatement("UPDATE bok_inf_tbl SET title=?,
author=?,price=?,publish=?,published=? WHERE isbn=?");
      }else{
        objPs2=db.prepareStatement("INSERT INTO bok_inf_tbl(title,
author,price,publish,published,isbn) VALUES(?,?,?,?,?,?)");
      }
      objPs2.setString(1,this.title);
      objPs2.setString(2,this.author);
      objPs2.setString(3,this.price);
      objPs2.setString(4,this.publish);
      objPs2.setString(5,this.published);
      objPs2.setString(6,this.isbn);
      objPs2.executeUpdate();
    } catch(Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if(objPs1!=null){objPs1.close();}
        if(objPs2!=null){objPs2.close();}
        if(db!=null)   {db.close();}
      } catch(Exception e){
        e.printStackTrace();
      }
    }
  }
}

 コードの詳細なロジックについては、コード内のコメントを参照してもらうとして、ここでは1点だけ特記しておくことにします。アクションフォームBeansからのプロパティ値の取得方法についてです。第4回でも紹介したように、DynaActionFormを使用した場合、プロパティ値にアクセスするのは、getメソッドの役割でした。しかし、通常のActionForm(またはValidatorForm)を使用した場合には、getterメソッド(getXXXXメソッド)を使用する必要があります。意外と間違えやすいポイントでもありますので、注意してください。

 すべての準備が完了したら、「個別更新画面」に何かしらエラーとなるような値を入力して、[保存]ボタンをクリックしてください。不正な値に対応するエラーダイアログが表示されれば成功です(完成図は冒頭の画面を参照してください)。

まとめ

 ところで、このValidatorプラグインがサーバサイドとクライアントサイドの両方の検証に対応していることに、疑問を持たれた方もいるかもしれません。サーバサイドとクライアントサイドでまったく同様の機能を実装するのは、一見無駄のようにも見えます。しかし、それでは、いずれか片方の機能をのみ有効にしておけばよいのでしょうか?

 答えは、否です。というのも、クライアントサイドの検証機能は、クライアントブラウザがJavaScriptに対応していない、またはJavaScriptを無効にしている状態の場合、必ずしも動作するとは限らないからです。確実性という意味で、最終的なデータのチェックは、サーバサイドで行う必要があります。ただ、サーバサイドでのみ検証チェックを行えばよいかというと、それも違います。データ検証のために、いつもクライアントとサーバ間にトラフィックが発生するのは、パフォーマンス上好ましいことではないからです。チェックできるものは、極力クライアント側で行ってしまった方が、パフォーマンス的にも、サーバ負荷の軽減という意味でも、より有効でしょう。

 そういう意味では、StrutsのValidatorプラグインは、いずれか一方への実装でさえ煩雑であった入力データのチェックを、設定ファイルだけでクライアントとサーバの両方に簡単に実装できるようにした点で、極めて画期的なものであるといえます。これで、開発者は、本当に重要なビジネスロジックの構築に集中することができるというわけです。

 本連載も次回がいよいよ最終回。最後のテーマでは、「書籍登録・更新アプリケーション」を例に、アプリケーションの国際化(i18n)対応を行う予定です。どうぞお楽しみに。


前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

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

メールマガジン登録

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