いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

DWR奮闘記-002(基本的な動作)

てことで、動作を確認したいので簡単なサンプルを作成しました。
動作させるためには、以下のものを用意します。

  • web.xml
  • dwr.xml
  • 連携するクラス
  • 画面HTML

ひとつずついきます。

[web.xml]

<?xml version="1.0" encoding="Windows-31J"?>
<!DOCTYPE web-app 
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

    <display-name>MyDWRSamples</display-name>
    <description>
        My DWR Samples
    </description>

    <!--
        各種フィルター定義
    -->
    <filter>
        <filter-name>requestEncodingFilter</filter-name>
        <filter-class>gsf.util.servlet.filter.UTF8EncodingFilter</filter-class>
    </filter>

    <filter>
        <filter-name>responseCharsetFilter</filter-name>
        <filter-class>gsf.util.servlet.filter.ShiftJISCharsetResponseFilter</filter-class>
    </filter>

    <!--
        各フィルターのマッピング
    -->
    <filter-mapping>
        <filter-name>requestEncodingFilter</filter-name>
        <url-pattern>/app/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>responseCharsetFilter</filter-name>
        <url-pattern>/app/*</url-pattern>
    </filter-mapping>

    <!--
        サーブレットの定義

        DWRサーブレットの定義
    -->
    <servlet>
        <servlet-name>DWRInvoker</servlet-name>
        <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>true</param-value>
        </init-param>
    </servlet>

    <!--
        サーブレットのマッピング
    -->
    <servlet-mapping>
        <servlet-name>DWRInvoker</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>

</web-app>

web.xmlには、DWRサーブレットを指定します。このサーブレットがJSとJAVAの連携を
行います。init-paramにdebugを指定しておくと

http://xxxxx/アプリ名/app/

にアクセスすると、連携できるクラスの一覧が表示されたりします。
これ、かなり便利ですので開発中はtrueにしておきましょう。

次は、DWRの設定ファイルです。
このファイルに、連携設定を書きます。

[dwr.xml]

<?xml version="1.0" encoding="Windows-31J"?>
<dwr>
    <allow>
        <convert converter="bean" match="gsf.samples.dwr.DWRSample001"/>
        <create creator="new" javascript="DWRSample001">
            <param name="class" value="gsf.samples.dwr.DWRSample001"/>
        </create>
    </allow>
</dwr>

最初のconvert要素は、javascript側で使用するための設定みたいです。
ドキュメントちゃんと読んでないのであまり意味わかってません・・。
多分、javascript内でjavaのbeanを使用する際に、設定する項目だと
おもいますので、今回のサンプルでは定義する必要がないかも・・。w
次は、連携クラスを設定。見たままですが、該当クラスをnewしてねって
お願いしています。

次は、連携クラス.
こちらは普通のクラスです。
DWRは実装には手を出してこないので何かのクラスを継承しなければ
ならないということはありません。そのままクラスを書きます。
通常、開発ではこの部分はDAOやサービスが連携モジュールになるでしょう。

// vim:set ts=4 sw=4 et ws is nowrap ft=java fenc=cp932 ff=dos:
package gsf.samples.dwr;

public class DWRSample001{

    public String toUpperCase(String message){
        if(message == null){
            return "";
        }

        try{ Thread.currentThread().sleep(500); }catch(Exception ex){}

        return message.toUpperCase();
    }
}

今回は、単に受け取ったデータを大文字にして返しているだけです。
ただ、それだと通信処理がすぐ終わってしまうので明示的に500ミリ秒
処理をとめてから戻しています。

最後に画面HTMLです。

<html>
<head>
    <script src="app/interface/DWRSample001.js"></script>
    <script src="app/engine.js"></script>
    <script src="app/util.js"></script>
    <script>
        function sendValue(){
            var field1Value = $("field1").value;

            if(field1Value != ""){
                DWRSample001.toUpperCase(field1Value, myCallBackFunction);

                $("statusArea").innerHTML = "バックグラウンドで通信中・・・・";
            }
        }

        function myCallBackFunction(upperCasedValue){
            $("field2").value = upperCasedValue;

            $("statusArea").innerHTML = "通信完了。";
        }
    </script>
</head>
<body>
    <br/>
    <br/>
    <hr/>
    <center>
        <span id="statusArea" style="color:red"></span>
        <br/>
        <input id="field1" type="text" name="field1" value="" onChange="sendValue();"/>
        <br/>
        <br/>
        <input id="field2" type="text" name="field2" value="" onFocus="document.getElementById('field1').focus();"/>
    </center>
    <hr/>
    <br/>
    <br/>
</body>
</html>

画面側での決まりごとは以下の点です。

  • 以下の3つをHEADタグ内でscript定義する。
    <script src="アプリ名/interface/[dwr.xmlで定義したjavascript属性の値].js"></script>
    <script src="アプリ名/engine.js"></script>
    <script src="アプリ名/util.js"></script>
  • サーバー側と連携する際、戻り値を受け取る場合は最後の引数にコールバック関数を渡す.

今回の画面では、myCallBackFunction関数がコールバック関数となります。
なぜ、

var returnValue = DWRSample001.toUpperCase(field1Value);

とせずに、コールバックが必要なのでしょうか。
答えは、この処理が非同期で実行されるからです。
同期実行なら処理が終わるまで待たされますが、非同期なので
メソッドコールしたらすぐに処理が戻ってきます。でも、サーバー側の処理が
終わったわけではないので、値が受け取れません。
そのため、終わり次第、こちらの処理が走るようにするわけです。
なのでコールバックが必要になります。
Ajaxアプリは通信が非同期で行われるので、この辺を理解して処理を
考えないといけません。


あとは、デプロイしたら完了です。

実際に画面を立ち上げると、入力フィールドが二つあり上の入力フィールドに値を
入力してエンターなどを押下するとサーバーとの連携が始まります。
連携が終わると下側の入力フィールドに大文字に変換された値が表示されます。

ちなみに、htmlのjavascriptソースコード内で

$("hoge").value

などとしている部分がありますが、これはprototype.jsにあるのと同じように

document.getElementById("hoge").value

のショートカット関数です。DWRUtil.jsに定義されています。

DWRのサイトは、ドキュメントが充実している模様ですので、ちょこちょこ
読んで理解していきたいとおもいます。