intra-mart Accel Platform Webサービス スクリプト開発プログラミングガイド 第2版 2014-04-01

Webサービス・クライアント の作成

作成手順の概要

この章では、Web サービスとして公開された関数を、スクリプト開発モデルから利用する手順を説明します。
スクリプト開発モデルでは、Web サービスを呼び出すための API 「SOAPClient オブジェクト」が用意されています。
SOAPClient オブジェクトを利用することにより、XML や Java を意識することなく、Web サービスを呼び出すことができます。
SOAPClient オブジェクトを利用した Web サービスの呼び出しは、以下の3つの手順で実現できます。
  1. WSDL を指定して SOAPClient オブジェクトのインスタンスを生成します。
  2. SOAPClient オブジェクトの引数に渡す WSUserInfo オブジェクトを生成します。
  3. SOAPClient オブジェクトを利用して Web サービスにアクセスします。
このチュートリアルでは、「Webサービス・プロバイダ の作成 」で解説されている Web サービスが呼び出されるまでを解説します。

コラム

SOAPClient オブジェクトを利用するための設定が用意されています。
SOAPClient の設定についての詳細は、「設定ファイルリファレンスの SOAPClient オブジェクトの設定 」を参照してください。

Webサービス へアクセスする画面を作成する

開発環境を用意する

Webサービス・プロバイダ の「開発環境を用意する 」と同様に開発環境(e Builder、Resin、および、intra-mart Accel Platform)をインストールします。
このチュートリアルでは、以下のプロジェクトを作成し、開発を行う手順を説明します。
グループID mypackage (デフォルトの設定を使用)
バージョン 1.0.0 (デフォルトの設定を使用)
プロジェクト名 sample_client
e Builder のインストールが完了したら、以下の手順に従って、「Module Project」でプロジェクトを作成します。
  1. 「ファイル」-「新規」-「プロジェクト」をクリックします。
  2. 「e Builder」-「Module Project」を選択して「次へ」をクリックします。
  3. プロジェクト名に「sample_client」を入力して、「終了」をクリックします。
プロジェクトの作成が完了したら、intra-mart Accel Platform の API を使用できるようにするために、プロジェクトの設定を行います。
  1. プロジェクトを右クリックして「プロパティ」を選択します。
  2. 「e Builder」-「Module Assembly」を選択します。
  3. Web アーカイブディレクトリに、war を展開してできたコンテキストパスと同名のフォルダを選択します。
  4. リソース変更時の自動デプロイ先の一覧で、全てのチェックボックスを外します。
  5. 「OK」をクリックします。

依存関係を解決する

プロジェクトの設定が完了したら、依存関係の修正を行います。
Webサービス・プロバイダ にアクセスするためには、「Webサービス 認証・認可クライアント」モジュールに依存する必要があります。
以下の手順に従って、プロジェクトの依存関係を修正します。
  1. 作成したプロジェクトのルートディレクトリに配置されている module.xml をダブルクリックします。

  2. 「依存関係」タブを開き、「追加」をクリックします。

  3. 以下の内容を入力して、「OK」をクリックします。

    ID jp.co.intra_mart.im_ws_auth_client
    バージョン 8.0.2

    コラム

    基本的にバージョンはサポートが行われている番号を指定します。
    使用したい API が他のバージョンに含まれている場合、そのバージョン番号を指定してください。
  4. module.xml ファイルを保存した後、「module.xml」タブを開き、不要なタグ(<tags>)を除去します。
    最終的なソースは以下です。
    <?xml version="1.0" encoding="UTF-8"?>
    <module conf:schemaLocation="urn:intramart:jackling:toolkit:configurations configurations.xsd"
            xmlns="urn:intramart:jackling:module" xmlns:conf="urn:intramart:jackling:toolkit:configurations"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemeLocation="urn:intramart:jackling:module module.xsd">
    
        <id>mypackage.sample_client</id>
        <version>1.0.0</version>
        <type>module</type>
        <name>${module.name}</name>
        <vendor>${module.vendor}</vendor>
        <description>${module.description}</description>
    
        <dependencies>
            <dependency>
                <module-id>jp.co.intra_mart.im_ws_auth_client</module-id>
                <verified-version min="8.0.2">8.0.2</verified-version>
            </dependency>
        </dependencies>
    </module>
    
  5. 「依存関係の階層」タブを開き、依存関係が解決されさまざまなモジュールが表示されていれば成功です。

スクリプト開発モデルで業務処理を作成する

プロジェクトの準備が完了したら、Web サービスにアクセスするための画面をスクリプト開発モデルで作成します。
ここでは、サンプルとして sample/web_service/client/member_info_operator.htmlsample/web_service/client/member_info_operator.js を用意します。
member_info_operator.html ファイルと member_info_operator.js ファイルを、プロジェクトの以下の場所に作成します。
  • src/main/jssp/src/sample/web_service/client/member_info_operator.html
  • src/main/jssp/src/sample/web_service/client/member_info_operator.js
member_info_operator.html のソースは以下の通りです。
<imart type="head">
<script type="text/javascript">
(function($) {
  $(function() {
    /**
     * メンバー情報の追加
     */
    $('#add').click(function() {
      var userCd = $('#userCd').val();
      var password = $('#password').val();
      var id = $('#memberId').val();
      var name = $('#memberName').val();
      var age = $('#memberAge').val();
      var married = $('#memberMarried').val();
      var birthDate = $('#memberBirthDate').val();

      try {
        $.ajax({
          async:false, cache:false, dataType:'text', type:'POST',
          url:'sample/web_service/client/member_info_operator/add', data:{
            'userCd':userCd,
            'password':password,
            'id':id,
            'name':name,
            'age':age,
            'married':married,
            'birthDate':birthDate
          },
          success:function(result) {
            imuiAlert(result == 'true' ? 'OK' : 'NG');
          },
          error:function() {
            imuiAlert('NG');
          }
        });
      } catch (ex) {
        imuiAlert('NG');
      }
    });

    /**
     * メンバー情報の検索
     */
    $('#find').click(function() {
      var userCd = $('#userCd').val();
      var password = $('#password').val();
      var id = $('#memberId').val();

      try {
        $.ajax({
          async:false, cache:false, dataType:'json', type:'POST',
          url:'sample/web_service/client/member_info_operator/find', data:{
            'userCd':userCd,
            'password':password,
            'id':id
          },
          success:function(result) {
            $('#memberId').val(result.id);
            $('#memberName').val(result.name);
            $('#memberAge').val(result.age);
            $('#memberMarried').val(result.married);
            $('#memberBirthDate').val(result.birthDate);
            imuiAlert('OK');
          },
          error:function() {
            imuiAlert('NG');
          }
        });
      } catch (ex) {
        imuiAlert('NG');
      }
    });

    /**
     * 全てのメンバー情報の検索
     */
    $('#findAll').click(function() {
      var userCd = $('#userCd').val();
      var password = $('#password').val();

      try {
        $.ajax({
          async:false, cache:false, dataType:'json', type:'POST',
          url:'sample/web_service/client/member_info_operator/findAll', data:{
            'userCd':userCd,
            'password':password
          },
          success:function(result) {
            imuiAlert(result.length);
          },
          error:function(a, b, c) {
            imuiAlert('NG');
          }
        });
      } catch (ex) {
        imuiAlert('NG');
      }
    });
  });
})(jQuery);
</script>
</imart>

<div class="imui-form-container-wide">
  <div class="imui-chapter-title">
    <h2>Web サービスにアクセスするユーザ情報</h2>
  </div>
  <table class="imui-form">
    <tbody>
      <tr>
        <th class="wd-20"><label class="imui-required">ユーザコード</label></th>
        <td><imart type="imuiTextbox" id="userCd" value="aoyagi" autofocus /></td>
      </tr>
      <tr>
        <th class="wd-20"><label class="imui-required">パスワード</label></th>
        <td><imart type="imuiTextbox" id="password" value="aoyagi" /></td>
      </tr>
    </tbody>
  </table>
  <div class="imui-chapter-title">
    <h2>登録するメンバー情報</h2>
  </div>
  <table class="imui-form">
    <tbody>
      <tr>
        <th class="wd-20"><label class="imui-required">ID (id)</label></th>
        <td><imart type="imuiTextbox" id="memberId" /></td>
      </tr>
      <tr>
        <th class="wd-20"><label>名前 (name)</label></th>
        <td><imart type="imuiTextbox" id="memberName" /></td>
      </tr>
      <tr>
        <th class="wd-20"><label>年齢 (age)</label></th>
        <td><imart type="imuiTextbox" id="memberAge" /></td>
      </tr>
      <tr>
        <th class="wd-20"><label>既婚フラグ (married) [true or false]</label></th>
        <td><imart type="imuiTextbox" id="memberMarried" /></td>
      </tr>
      <tr>
        <th class="wd-20"><label>誕生日 (birthDate) [yyyy-mm-dd 形式]</label></th>
        <td><imart type="imuiTextbox" id="memberBirthDate" /></td>
      </tr>
    </tbody>
  </table>
  <div class="imui-operation-parts">
    <imart type="imuiButton" id="add" value="add" class="imui-large-button" />
    <imart type="imuiButton" id="find" value="find" class="imui-large-button" />
    <imart type="imuiButton" id="findAll" value="findAll" class="imui-large-button" />
  </div>
</div>
member_info_operator.js のソースは以下の通りです。
// ホスト名、ポート番号、コンテキストパスは適宜置き換えてください。
var wsdlURL = 'http://localhost:8080/imart/services/SampleMemberInfoOperatorService?wsdl';

/**
 * 初期化
 */
function init() {
}

/**
 * 認証情報の取得
 */
function getWSUserInfo(userCd, password) {
    return {
        'userID':userCd,
        'password':WSAuthDigestGenerator4WSSE.getDigest(userCd, password),
        'authType':WSAuthDigestGenerator4WSSE.getAuthType(),
        'loginGroupID':'default' // 実際にはプロバイダから提供された接続先ログイングループID/テナントIDを設定します。
    };
}

/**
 * メンバー情報の追加
 */
function add(request) {
    try {
        var userCd = request.userCd;
        var password = request.password;
        var member = {
            'id':request.id,
            'name':request.name,
            'age':request.age,
            'married':request.married == 'true',
            'birthDate':DateTimeFormatter.parseToDate(DateTimeFormatter.STANDARD_DATE_FORMAT_PATTERN, request.birthDate),
            'children':[]
        };

        var soapClient = new SOAPClient(wsdlURL);
        var wsUserInfo = getWSUserInfo(userCd, password);
        var result = soapClient.add(wsUserInfo, member);
        Debug.console('処理が成功しました。', result);
        outputText(result ? 'true' : 'false');
    } catch (ex) {
        Debug.console('エラーが発生しました。', ex);
        throw ex;
    }
}

/**
 * メンバー情報の検索
 */
function find(request) {
    try {
        var userCd = request.userCd;
        var password = request.password;
        var id = request.id;

        var soapClient = new SOAPClient(wsdlURL);
        var wsUserInfo = getWSUserInfo(userCd, password);
        var result = soapClient.find(wsUserInfo, id);
        Debug.console('処理が成功しました。', result);

        var member = {
            'id':result.id,
            'name':result.name,
            'age':result.age,
            'married':result.married ? 'true' : 'false',
            'birthDate':DateTimeFormatter.format(DateTimeFormatter.STANDARD_DATE_FORMAT_PATTERN, result.birthDate)
        };
        outputJSON(member);
    } catch (ex) {
        Debug.console('エラーが発生しました。', ex);
        throw ex;
    }
}

/**
 * 全てのメンバー情報の検索
 */
function findAll(request) {
    try {
        var i;
        var userCd = request.userCd;
        var password = request.password;

        var soapClient = new SOAPClient(wsdlURL);
        var wsUserInfo = getWSUserInfo(userCd, password);
        var result = soapClient.findAll(wsUserInfo);
        Debug.console('処理が成功しました。', result);

        var members = [];
        for (i = 0; i < result.length; i++) {
            members.push({
                'id':result[i].id,
                'name':result[i].name,
                'age':result[i].age,
                'married':result[i].married ? 'true' : 'false',
                'birthDate':DateTimeFormatter.format(DateTimeFormatter.STANDARD_DATE_FORMAT_PATTERN, result[i].birthDate)
            });
        }
        outputJSON(members);
    } catch (ex) {
        Debug.console('エラーが発生しました。', ex);
        throw ex;
    }
}

function outputText(text) {
    var response = Web.getHTTPResponse();
    response.setContentType('text/plain; charset=utf-8');
    response.sendMessageBodyString(text);
}

function outputJSON(object) {
    var response = Web.getHTTPResponse();
    response.setContentType('application/json; charset=utf-8');
    response.sendMessageBodyString(ImJson.toJSONString(object));
}

コラム

SOAPClient API を利用して Web サービスを呼び出す前に、認証・認可用のユーザ情報を設定します。
このサンプルでは、認証タイプ「WSSE」を利用しています。
認証タイプ「WSSE」の詳細は「Webサービス 認証・認可 仕様書」-「認証・認可」を参照してください。
サンプルでは WSAuthDigestGenerator4WSSE オブジェクトを利用してパスワード・ダイジェストを作成しています。
認証タイプ「WSSE」は、パスワードのダイジェスト化方法に、WS-Security の UsernameToken 形式を採用しています。
WSAuthDigestGenerator4WSSE オブジェクトは、そのパスワード・ダイジェストの生成に特化したユーティリティです。
「ユーザコード」と「パスワード」を元にパスワード・ダイジェストを生成します。

コラム

wsUserInfoに設定する情報については、Webサービスプロバイダ側の設定と合わせる必要があります。
サンプルでは「getWSUserInfo」メソッド内で、wsUserInfoの情報を定義しています。

コラム

SOAPClient API を使うためのサンプルコードは、SOAPClient オブジェクトの「getSampleCode()」から取得することができます。
以下のようなコードを実行することで、「add()」関数を呼び出すためのサンプルコードがコンソール上に出力されます。
// ホスト名、ポート番号、コンテキストパスは適宜置き換えてください。
var wsdlURL = 'http://localhost:8080/imart/services/SampleMemberInfoOperatorService?wsdl';
var soapClient = new SOAPClient(wsdlURL);
var sampleCode = soapClient.getSampleCode("add");
Debug.console(sampleCode);
SOAPClient オブジェクトの詳細は、「API リストの SOAPClient オブジェクト 」を参照してください。

コラム

Web サービスの結果が SOAPFault エラーをスローした場合、SOAPClient オブジェクトの関数を実行した際に SOAPFault オブジェクトが例外としてスローされます。
SOAPFault オブジェクトは、XML 形式の SOAPFault を JavaScript のオブジェクト形式に変換したものです。
SOAPFault オブジェクトを捕捉するためには、Web サービスのオペレーション実行部分を try ~ catch 文で囲んでください。
catch 内で SOAPFault オブジェクトを利用したエラー処理を行うことができます。
SOAPFault オブジェクトの詳細は、「API リストの SOAPFault オブジェクト 」を参照してください。
なお、Webサービス・プロバイダ 側では、Web サービス呼び出し時に設定した認証情報(WSUserInfo)を元に認証・認可が行われます。
該当するユーザが存在しない、パスワードが間違っているなどの理由でユーザ情報が不正な場合、または、Web サービスを実行する権限がない場合には、SOAPFault オブジェクトが例外としてスローされます。
SOAPFault オブジェクトの「faultCode」プロパティには、発生した問題に対応するコードが含まれています。
コードについての詳細は「Webサービス 認証・認可 仕様書」-「認証・認可のSOAPフォルト・コード」を参照してください。

ルーティングテーブルを登録する

画面の作成が完了したら、画面にアクセスするためのルーティングテーブルを登録します。
sample_member_info.xml ファイルを、プロジェクトの以下の場所に作成します。
  • src/main/conf/routing-jssp-config/sample_member_info.xml
sample_member_info.xml のソースは以下の通りです。
<?xml version="1.0" encoding="UTF-8"?>
<routing-jssp-config xmlns="http://www.intra-mart.jp/router/routing-jssp-config"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.intra-mart.jp/router/routing-jssp-config routing-jssp-config.xsd">

    <authz-default mapper="welcome-all" />

    <file-mapping path="/sample/web_service/client/member_info_operator"
        page="sample/web_service/client/member_info_operator">
    </file-mapping>

    <file-mapping path="/sample/web_service/client/member_info_operator/add"
        page="sample/web_service/client/member_info_operator" action="add">
    </file-mapping>

    <file-mapping path="/sample/web_service/client/member_info_operator/find"
        page="sample/web_service/client/member_info_operator" action="find">
    </file-mapping>

    <file-mapping path="/sample/web_service/client/member_info_operator/findAll"
        page="sample/web_service/client/member_info_operator" action="findAll">
    </file-mapping>

</routing-jssp-config>

Webサービス へアクセスする画面をデプロイする

資材をデプロイする

以上で Web サービスを実行するための資材が完成しました。
次に作成したモジュールをユーザモジュールとして取り込み、war を作成して Resin にデプロイします。
以下の手順に従って、e Builder でユーザモジュールを作成します。
  1. プロジェクトを右クリックして、「エクスポート」を選択します。
  2. 「e Builder」-「imm file」を選択して、「次へ」をクリックします。
  3. 出力先フォルダに任意の場所を選択して、「終了」をクリックします。
  4. しばらくすると、出力先フォルダに sample_client-1.0.0.imm ファイルが作成されます。
次に、以下の手順に従って、e Builder で imm ファイルをユーザモジュールとして取り込みます。
  1. e Builder で環境構築時に利用したプロジェクトの「juggling.im」を開きます。

  2. 「ユーザモジュール」タブを開き、右上の「モジュールを追加します」アイコンをクリックします。

  3. e Builder で作成した sample_client-1.0.0.imm ファイルを選択して開きます。

    コラム

    依存関係が不足している場合、上側にエラーメッセージが表示されます。
    この場合、エラーメッセージをクリックして不足しているモジュールを追加してください。
  4. juggling.im を保存して、環境構築時と同じ手順で war を作成し、Resin にデプロイします。

  5. Resin を再起動します。

次に、以下の手順に従って、テナント環境セットアップを実施します。
  1. システム管理画面を開き、システム管理者でログインします。
    http://<HOST>:<PORT>/<CONTEXT_PATH>/system/login
  2. 「テナント環境セットアップ」をクリックします。

    コラム

    「テナント環境は最新です。セットアップが必要なモジュールはありません。」が表示されている場合は、以降の操作は不要です。
  3. 続けて「テナント環境セットアップ」をクリックします。

  4. 確認メッセージで「決定」をクリックします。

Webサービス にアクセスする

Resin の再起動とテナント環境セットアップが完了したら、作成した画面にアクセスして Web サービスを実行します。
  • 以下の手順に従って、メンバー情報を登録します。

    1. 以下の URL にアクセスします。
      http://<HOST>:<PORT>/<CONTEXT_PATH>/sample/web_service/client/member_info_operator
    2. 以下のような画面が表示されることを確認します。

      ../../_images/client_1.png

    3. 以下の内容を入力して、「add」をクリックします。

      id test
      name テストユーザ
      age 30
      married true
      birthDate 1982-06-12
    4. 「OK」と表示されれば成功です。

  • 以下の手順に従って、メンバー情報を検索します。

    1. 以下の内容を入力して、「find」をクリックします。

      id test
      name (空欄)
      age (空欄)
      married (空欄)
      birthDate (空欄)
    2. 「OK」と表示され、以下の内容が表示されれば成功です。

      id test
      name テストユーザ
      age 30
      married true
      birthDate 1982-06-12
  • 以下の手順に従って、メンバー情報の件数を表示します。

    1. 「findAll」をクリックします。

    2. 「1」と表示されれば成功です。

      コラム

      「add」で追加した分のメンバー情報の件数が表示されます。