Page   | 1  | 2  | 3  |

Yahoo UIライブラリを使った
Ajax+DBアプリケーション開発の実践
 
翔泳社『DBマガジン』2006年6月号
「AjaxでDBプログラミング」に掲載
 
中村正弘

前パートまでに解説したAjaxおよびJavaScriptの基本知識を踏まえて、本パートではAjaxとDBを組み合わせたWebアプリケーションを開発してみる。DBからのデータ取得には、サーバーサイドのJavaメソッドを簡単に呼び出せるJSON-RPC-Javaフレームワークを利用し、ユーザー画面の作成には今話題のYahoo UIライブラリを使う。最後にクロスブラウザやセキュリティ問題など、Ajaxでアプリケーションを開発する際の注意点も述べる。

ブックマーク登録機能の実装

それでは、それぞれの機能の実装を見ていこう。最初は、ブックマーク登録機能である。
この機能は、ユーザーがブックマークしたいと思ったWebページのタイトル、URL、ユーザーのコメントをDBに格納する、という処理を行なう。ごく単純な処理ではあるが、この処理を一切のページ遷移なしに実現している部分がAjaxらしいところである。
登録機能を実現するのは、2つのJSPページ(Bookmark.jsp、RegistBookmark.jsp) と1つのJavaクラス(Bookmarkクラス)だ。全体の処理の流れは、図3のとおりである。

図3 ブックマーク登録機能の処理の流れ

Bookmark.jsp

LIST3をご覧いただきたい。このJSPページは、はてなブックマーク(注1)にならって、さまざまなWebページを手軽にブックマークするためのスクリプト(JavaScriptで記述)を、Webブラウザの「お気に入り」に登録してもらうための、ごく簡単なJSPページである。このJSPページをコンテキスト内に置き、http://localhost/Bookmark.jsp(URLはJSPページが置かれたコンテキストによって異なる)にアクセスすると、画面1のように表示される。「ブックマーク登録」というハイパーリンクがあるのでこれを右クリックし、表示されたコンテキストメニューから[お気に入りに追加]を選べば、スクリプトの登録は完了だ。
あとは、登録したいWebページを表示し、お気に入りからこのスクリプトを呼び出せば、簡単にブックマーク登録用の画面を表示することができるというわけである。

LIST3 Bookmark.jsp

<%@ page contentType="text/html; charset=shift_jis" %>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
        <body>
            以下のURLはブックマークを追加するためのスクリプトです。<br>
            リンクを右クリックしてお気に入りに追加してください。<br>
            <a href="javascript:window.open(’http://localhost/RegistBookmark.jsp?title=’ ⇒
            +escape(document.title)+’&url=’+escape(location.href),%20 ⇒
            ’_blank’,%20’width=400,height=300’);undefined;">ブックマーク登録</a>
        </body>
    </head>

(※誌面の都合により、“⇒”で折り返す。以下同)

画面1 ブックマーク用スクリプトを登録するページ

RegistBookmark.jsp

次に紹介するのは、ブックマーク登録用のページ(画面2)を表示するためのJSPページである。先ほどお気に入りに登録したスクリプトから呼び出されて、登録するURLに対するタイトルとコメントの入力をユーザーに求める。[登録]ボタンがクリックされると、サーバー側にある登録用のメソッドを呼び出す仕組みだ。
まずは、LIST4をご覧いただきたい。ここでは、本格的にAjaxのコードが現われている。ポイントとなる部分を詳細に見ていこう。
まず①では、JSONRPCBridgeオブジェクトを、Servlet APIが用意しているHttpSessionオブジェクトに関連付けている。これは、JSON-RPC-Javaを利用する上での決まりごととして必ず行なう。
②では、JSONRPCBridgeにBookmarkのクラスオブジェクトを登録している。これにより、Bookmarkクラスが保持しているすべてのstaticメソッドがJavaScript経由で使えるようになる。
registerClassメソッドは、第1引数として指定した名前に、第2引数でサーバー側にあるメソッドを提供するJavaクラスのクラスオブジェクトを紐付けてくれる。これにより、JavaScriptからは第1引数で指定した名前を使ってサーバー側のメソッドを呼び出せるようになる。後の⑤では、ここで指定したBookmarkという名前を使って、BookmarkクラスのregistBookmarkメソッドをJava Scriptから呼び出している。
なお、第2引数に指定するのはクラスオブジェクトであって、インスタンスではない点に注意していただきたい。インスタンスメソッドを公開する場合には、registerClassメソッドではなく、registerObjectメソッドを使用する。
③では、JSON-RPC-Javaのクライアント側で利用するライブラリを読み込んでいる。
④からはJavaScriptの記述に入っている。ここでは、Webページを読み込んだときにブラウザが呼び出す関数(onLoad)の中で、JSONRpcClientオブジェクトを生成している。以降は、このオブジェクトを介してサーバー側のメソッドを呼び出せるようになる。
⑤のregistBookmarkは、登録処理を実行するJavaScriptの関数である。[登録]ボタンがクリックされると呼び出されて、フォームに入力されている内容を取得し、サーバー側のregistBookmarkメソッドを呼び出す。ここでは、その呼び出し方に注目してほしい。var result=jsonrpc.Bookmark.registBookmark(url, title, comment);と、あたかもローカルにあるメソッドを呼び出すようにサーバー側のJavaメソッドを呼び出している。XMLHttpRequestオブジェクトやJSONを意識する必要はないのである。この部分を見るだけでも、JSON-RPC-Javaが非常に強力かつ有用なフレームワークであることが分かると思う。
なお、registBookmarkメソッドは、戻り値としてboolean(真偽値)を返すようになっている。このような実装では、コードにあるとおり、JavaScriptでもそのまま真偽値として評価可能である。もう少し複雑なデータ構造を扱う場合には別の手段が必要であるが、それは後述する。
⑥以降は、ほとんどが普通のHTMLフォームである。このJSPページは、基本的にJavaScriptからパラメータ付きで呼び出されることを想定しており、パラメータの値(ブックマーク対象ページのURLやタイトル)をフォーム内に表示している。また、フォームのsubmit( 送信)イベントを拾って、登録処理を行なうJavaScript関数が呼び出されるようにしている。

画面2 ブックマーク登録用のJSPページ

Bookmark.java(registBookmarkメソッド)

さて、登録処理の最後はサーバー側のJavaクラスである。LIST5をご覧いただきたい。このクラスは2つのpublicメソッドを持っているが、ここでは、registBookmarkメソッドを見ていただきたい。このメソッドは、RegistBookmark.jspから送られてくるブックマーク対象ページのURL、タイトル、ユーザーが入力したコメントをパラメータとして受け取り、SQL文を組み立てて、JDBCを使ってDBに登録している。
テーブルbookmarkの主キーは「URL」である。もし、すでに同じURLが存在していれば更新処理を、そうでなければ新規にレコードを追加する処理を行なっている。おおまかなフローは以下のとおりである。
 
① パラメータで受け取ったURLを持つ行を取得するSELECT文を実行する
② ResultSet#nextメソッドがtrueを返せば、同一のURLを保持する行が存在するということになるので、UPDATE文を実行してbookmarkテーブルのcount列の値をインクリメントし、last_update列を現在の時刻で更新する
③ ResultSet#nextメソッドがfalseを返せば、同一のURLを保持する行が存在しないということになるので、INSERT文を実行して新規にレコードを追加する
 
処理そのものはごく普通のJDBCを使った処理なので、特に変わった点はない。しかし、このごく普通の、ServletですらないJavaクラスのメソッドを、クライアント側のJavaScriptかDB Magazine 2006 June 087ら呼び出せるという点は注目に値する。JSON-RPC-Javaを利用すれば、極端な話、Servlet APIすらほとんど知らなくてもサーバー側のコードを書くことができるのである。
また、RegistBookmark.jspの説明でも述べたが、このregistBookmarkメソッドは戻り値としてboolean値を返している。JSON-RPCJavaでは、JavaScriptとサーバーアプリケーションとの間のメッセージのやり取りにJSONを使っているのだが、このようなJavaの型とJSON形式への変換はすべてJSON-RPCJava のフレームワークが面倒を見てくれるのである。サーバー側の開発者はJSON形式を意識する必要はない。
なお、LIST5では、MySQLのデータベース名として“user_db”を、接続ユーザーとして“root”を、rootのパスワードとして“pwd”をそれぞれ指定している。この部分は読者の環境に合わせて変更していただきたい。

LIST4 Bookmark.jsp

<%@ page contentType="text/html; charset=shift_jis" %>
<jsp:useBean  scope="session"
    class="com.metaparadigm.jsonrpc.JSONRPCBridge" />                 ・・・・①
<% JSONRPCBridge.registerObject("Bookmark", sample.Bookmark.class); %>・・・・②
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
        <title>ブックマーク登録</title>
        <script type="text/javascript" src="/jsonrpc.js"></script>    ・・・・③
        <script type="text/javascript">
    <!--
    function onLoad() {                                        ・・・・④
        jsonrpc = new JSONRpcClient("/JSON-RPC");
    }
    function registBookmark() {                                       ・・・・⑤
        var url = document.getElementById("url").innerHTML;
        var title = document.getElementById("title").value;
        var comment = document.getElementById("comment").value;
        var result = jsonrpc.Bookmark.registBookmark(url, title, comment);
        var elem = document.getElementById("registResult");
        if(result) {
            elem.innerHTML = "登録が完了しました。";
            elem.style.color = "black";
        } else {
            elem.innerHTML = "登録に失敗しました。";
            elem.style.color = "red";
        }
        return false;

    }
    // -->
    </script>
    </head>
    <body onload="onLoad()">
        <p>ブックマーク登録</p>
        <form onSubmit="return registBookmark();">                     ・・・・⑥
            <table border="0">
            <tr>
            <td align="right">URL:</td>
            <td><div ><%=request.getParameter("url")%></div></td>
            </tr>
            <tr>
                <td align="right">タイトル:</td>
                <td><input type="text"  size="50" 
                value="<%=request.getParameter("title")%>"></td>
            </tr>
            <tr>
                <td align="right">コメント:</td>
                <td><input type="text"  size="50"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="登録">
                <div ></div></td>
                </table>
        </form>
    </body>
</html>

LIST5 Bookmark.java

package sample;
import java.util.*;
import java.text.*;
import java.sql.*;
public class Bookmark {
    private static Connection con = null;
    private static Statement stmt = null;
    static {
        try {
            Class.forName("org.gjt.mm.mysql.Driver");
            con = DriverManager.getConnection("jdbc:mysql:///user_db", "root", "pwd");
            stmt = con.createStatement();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    public static boolean registBookmark(String url, String title, String comment) {
        StringBuffer querySQL = new StringBuffer();
        querySQL.append("select * from bookmark where url = ’").append(url).append("’");
        boolean result = true;
        ResultSet rs = null;
        try {
            rs = stmt.executeQuery(querySQL.toString());
            if(rs.next()) {
                // ブックマークカウントを増やす
                int count = rs.getInt("count");
                count++;
                StringBuffer updateSQL = new StringBuffer();
                updateSQL.append("update bookmark set count=").append(count).append(",");
                updateSQL.append("last_update="); ??
                updateSQL.append("’").append(getCurrentDateStr()).append("’");
                updateSQL.append(" where url=’").append(url).append("’");
                stmt.executeUpdate(updateSQL.toString());
            } else {
                // 新規に追加する
                StringBuffer insertSQL = new StringBuffer();
                insertSQL.append("insert into bookmark values(");
                insertSQL.append("’").append(url).append("’,");
                insertSQL.append("’").append(title).append("’,");
                insertSQL.append("’").append(comment).append("’,");
                insertSQL.append("1,");
                insertSQL.append("’").append(getCurrentDateStr()).append("’)");
                stmt.executeUpdate(insertSQL.toString());
            }
            result = true;
        } catch(Exception e) {
            e.printStackTrace();
            result = false;
        } finally {
            try {
                rs.close();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }
    public static List getBookmarks(String startDate) {
        StringBuffer querySQL = new StringBuffer();
        querySQL.append("select * from bookmark");
        if(startDate.equals("")) {
            // すべてのレコードを返す(where 条件は書かない)
        } else {
            // 一部のレコードのみ取得
            querySQL.append(" where last_update > ");
            querySQL.append("’").append(startDate).append("’");
        }
        querySQL.append(" order by last_update desc");
        ResultSet rs = null;
        List list = new ArrayList();
        try {
            rs = stmt.executeQuery(querySQL.toString());
            while(rs.next()) {
                HashMap map = new HashMap();
                map.put("url", rs.getString("url"));
                map.put("title", rs.getString("title"));
                map.put("note", rs.getString("note"));
                map.put("count", rs.getString("count"));
                java.util.Date date = rs.getTimestamp("last_update");
                map.put("last_update", toDateString(date));
                list.add(map);
            }
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            try {
                rs.close();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
        return list;
    }
    private static String getCurrentDateStr() {
        java.util.Date today = new java.util.Date();
        SimpleDateFormat df = new SimpleDateFormat();
        df.applyPattern("yyyy-MM-dd HH:mm:ss");
        return df.format(today);
    }
    private static String toDateString(java.util.Date date) {
        SimpleDateFormat df = new SimpleDateFormat();
        df.applyPattern("yyyy-MM-dd HH:mm:ss");
        return df.format(date);
    }
}

 

(注1)ソーシャルブックマークサービスの1 つ(http://b.hatena.ne.jp/)。ブックマーク登録に便利なスクリプトを提供しており、これをブラウザの「お気に入り」に登録しておき、ブックマークしたいWebページを開いた状態でお気に入りから選択すると、そのスクリプトが実行されてサーバーに登録される仕組みになっている。

Page   | 1  | 2  | 3  |

このサイトについてプライバシーポリシーサイトマップ

お問合わせ

Copyright (C) 2000-2011 UL Systems, Inc. All Rights Reserved.