とても簡単だ。
以下のコードは
Force.com開発者コースでもらった
サンプルコードですが、
見てもらって分かるとおり
すでにApexコードが実装されているのであれば
あとはWSDLをダウンロードできる状態にするために
クラス委定義にglobalキーワードを加え
公開するwebserviceキーワードを追加するだけだ。
こうすれば
設定画面のApexクラス一覧からWSDLがダウンロードできるようになる。
// Apex Code 演習8-1 カスタムSOAP Webサービス(1)
// EmployeeReferralタブのVisualforce画面から入力しsaveボタン押下
// →CandidateKeyWebService#submitEmployeeReferral()をSOAP API呼び出し
// →CandidateレコードとJobApplicationレコードを格納する
//
// Webサービスとして呼び出すクラスはglobalでなくてはならない
global class CandidateKeyWebService {
// Webサービス呼び出しメソッドは webServiceキーワードをつける
// EmployeeReferralタブ上のページから呼び出され
// 応募者(Candidate__c)レコードと申込(JobApplication__c)レコードを
// 新規追加する
// ただしすでに存在する応募者の場合は応募者レコードは追加しない
//
// 引数: posId 申込レコード上の募集職種ID(参照項目)
// c 応募者レコード
// 戻り値: 真:成功、偽:失敗
webService static Boolean submitEmployeeReferral(
String posId, Candidate__c c){
// 応募者レコード作成フラグ
boolean cCreate = true;
// 項目Emailが設定されている場合、重複チェックをかける
if (c.Email__c != null){
// LastNameとEmailを連結した文字列を作成
String uKey =
c.Last_Name__c.toLowerCase() +
c.Email__c.toLowerCase();
// unique_key(自動計算される項目)と突き合わせ、
// 1件以上存在すれば重複
if ([select count()
from Candidate__c
where unique_key__c = :uKey] >= 1){
// 既に存在する→作成フラグを偽に変更
cCreate=false;
// 引数cを既存レコードのForce.com IDに変更
// limit 1を付けると最初の1件をとることができる
c = [select Id
from Candidate__c
where unique_key__c = :uKey limit 1];
}
}
// エラーフラグ
boolean err = false;
// 応募者レコードを新規作成する必要がある場合
if (cCreate){
try{
// 新規追加
insert c;
// DBエラーの場合
} catch (System.DmlException e) {
// エラーフラグを真にする
err = true;
// デバッグログへ例外情報を記述
System.debug(
'error bulk inserting new candidate record');
for (Integer k = 0; k < e.getNumDml(); k++) {
System.debug(e.getDmlMessage(k));
}
}
}
// 応募者レコード新規追加に成功、もしくは既存レコードが存在し
// 新規追加操作をしていない場合
// 応募者レコード新規格納失敗の場合に申込レコードのみを追加
// してしまうとDBの整合性が荒れてしまうので
if (!err){
// 新規申込レコードを作成
Job_Application__c j = new Job_Application__c();
j.Status__c = 'Open'; // Status値をOpenに設定
j.Stage__c = 'New'; // Stage値をNewに設定
j.Position__c = posId; // Position値を引数posIdに設定
j.Candidate__c = c.Id; // Candidate値を応募者IDに設定
try{
// 申込レコードを新規追加する
insert j;
// DBエラーの場合
} catch (System.DmlException e) {
// デバッグログに例外情報を格納
System.debug(
'error bulk inserting new job application');
for (Integer k = 0; k < e.getNumDml(); k++) {
System.debug(e.getDmlMessage(k));
}
// 本来はエラーフラグを立て後続のハンドリング
// 処理判定に使用する
}
}
// エラーがない場合
if (!err) {
// 真を返却
return true;
// エラーが発生した場合
} else {
// 本来はエラーハンドリング処理をここに書く
// たとえばErrorLogレコードに格納する、など
// 偽を返却
return false;
}
}
}
できあがったWSDLをAXIS2の
wsdl2java
へかませばJavaから呼び出せるし
VisualStudioにかませれば
そっくりAPI呼び出し準備が完了する。
ただこの研修では
SOAPクライアント側をSalesforceが用意する
JavaScriptライブラリを利用して使用している
サンプルを紹介している。
Visualforceページになっているが
呼び出ししている
SOAP API呼び出しは
まるまるJavaScriptなので
apexタグを知らなくても読めると思う。
<!-- Apex Code 演習8-1 カスタムSOAP Webサービス(1) -->
<!-- EmployeeReferralタブのVisualforce画面から入力しsaveボタン押下 -->
<!-- →CandidateKeyWebService#submitEmployeeReferral()をSOAP API呼び出し -->
<!-- →CandidateレコードとJobApplicationレコードを格納する -->
<!-- controllerは定義されていない→JavaScriptからSOAP APIを呼び出している -->
<apex:page >
//Note that if the org password is NOT 'password1' that you will need to change it twice below!
<!-- Visualforceは終了タグを明記しないとエラーになる -->
<script type="text/javascript" src="/js/functions.js"></script>
<script src="/soap/ajax/17.0/connection.js"></script>
<script src="/soap/ajax/17.0/apex.js" type="text/javascript"></script>
<script type="text/javascript">
<!-- 入力チェックを実施、すべてOkならばsave()を実行 -->
function validate(){
<!-- connection.js上のメソッドを呼び出し -->
<!-- $Api/$APIはSalesforce上のメタデータを入手する際に -->
<!-- 使用するキーワード、ほかにも$Referenceなどがある -->
sforce.connection.init(
"{!$API.Session_ID}", "{!$Api.Partner_Server_URL_140}");
<!-- 判定結果格納用変数 -->
var ok2Go = true;
<!-- preSelectorリストボックスの選択値を取得 -->
var ps = document.getElementById("posSelector");
if (ps.options.length != 0){
var posId = ps.options[ps.selectedIndex].value;
}
<!-- 選択値がnullもしくは空文字の場合 -->
if ((posId == null)||(posId == "")) {
<!-- ダイアログでアラート表示し判定結果をNGに -->
alert("A position must be selected");
ok2Go = false;
}
<!-- form"refForm"内のID値"lastname"の値を取得 -->
var ln = document.forms["refForm"].elements["lastname"].value;
<!-- lastname値が空文字もしくはnullの場合 -->
if ((ln == "")||(ln == null)){
<!-- ダイアログでアラート表示し判定結果をNGに -->
alert("Last name is required");
ok2Go = false;
}
// form"refForm"内のID値"email"の値を取得 -->
var email = document.forms["refForm"].elements["email"].value;
<!-- email値が空文字もしくはnullの場合 -->
if ((email == "")||(email == null)){
<!-- ダイアログでアラート表示し判定結果をNGに -->
alert("Email is required");
ok2Go = false;
}
<!-- 判定結果OKの場合 -->
if (ok2Go) {
<!-- save()を呼び出しCandidateレコードを追加 -->
<!-- 引数posIdは-->
save(posId);
<!-- 判定結果NGの場合 -->
} else {
<!-- 戻り値falseを返す -->
return false;
}
}
<!-- ※使用されていない※ -->
<!-- グローバルオブジェクトの情報を入手する -->
<!-- apexドキュメントをdescribeGlobalで検索→サンプルコード参考の事 -->
function doDescribeGlobal(){
try{
var dgResults = sforce.connection.describeGlobal();
} catch (e) {
sforce.debug.open();
sforce.debug.log(e);
}
return dgResults;
}
<!-- ※使用されていない※ -->
<!-- グローバルSObjectの情報を入手する -->
<!-- apexドキュメントをdescribeSObject検索→サンプルコード参考の事 -->
function doDescribeSObject(entity){
try{
var dso = sforce.connection.describeSObject(entity);
}catch (e) {
sforce.debug.open();
sforce.debug.log(e);
}
return dso;
}
<!-- 引数で与えられたIDのリストボックス内のオプションをクリア -->
function clearSelect(name){
<!-- IDからオブジェクトを入手 -->
var sel = document.getElementById(name);
<!-- 空になるまでループ -->
while (sel.length > 0){
<!-- 先頭のオプションを削除 -->
sel.remove(0);
}
}
<!-- Department欄が選択されたら呼び出される -->
<!-- Department欄の状態によってposSelectorリストボックスを更新する -->
function deptChanged(department){
<!-- connection.jsを使用してコネクションを張る -->
sforce.connection.init("{!$API.Session_ID}", "{!$Api.Partner_Server_URL_140}");
<!-- IDが"posSelector"のリストボックス(Open Positions)を -->
<!-- クリア -->
clearSelect("posSelector");
<!-- 選択された部門(Department)に合致する募集職種レコード -->
<!-- を取得するクエリ文字列構築 -->
var qStr = "select Id, Name, Location__c, Department__c, Type__c, Status__c from Position__c where Status__c='Open' and Department__c = '" + department + "'";
try{
<!-- クエリを実行し結果を取得 -->
var queryResults = sforce.connection.query(qStr);
<!-- 1件以上取得できたら'records'レコード情報を -->
<!-- 配列として取得 -->
if (queryResults != null){
if (queryResults.size > 0){
var records = queryResults.getArray('records');
}
}
<!-- 例外発生時処理 -->
} catch (e){
<!-- Salesforceデバッグログへ例外情報を書き込む -->
sforce.debug.open();
sforce.debug.log(e);
}
<!-- IDが"posSelector"であるオブジェクトを取得 -->
var ps = document.getElementById("posSelector");
<!-- 結果が存在する場合 -->
if (records != null){
<!-- 結果レコードの全件ループ -->
for (var i=0; i<records.length; i++) {
<!-- JavaScriptのDOMを使ってoptionタグを -->
<!-- 新規生成 -->
var optNew = document.createElement('option');
<!-- value属性値としてPosition__cの -->
<!-- Force.com ID値を設定 -->
optNew.value = records[i].Id;
<!-- text属性値としてPosition__cのNameと -->
<!-- Location__c、Type__cを連結した文字列 -->
<!-- を設定 -->
optNew.text = records[i].Name + " : " + records[i].Location__c + " : " + records[i].Type__c;
<!-- IEのDOM方言対応のためのtry-catch句 -->
try {
<!-- posSelectorリストボックスの -->
<!-- オプションとして格納 -->
ps.add(optNew, null); // IE以外の場合
<!-- 例外発生時(IE)処理 -->
} catch(ex) {
<!-- IEの場合は引数1つらしい -->
ps.add(optNew); // IE の場合
}
}
}
}
<!-- 応募者レコードを新規格納する関数 -->
<!-- 引数posId: 応募者レコードに紐づける募集職種レコードID -->
function save(posId){
<!-- Candidate__c(応募者)レコードを新規生成
var candidate = new sforce.SObject("Candidate__c");
<!-- firstname値を応募者レコードのFirst_Name__cへ設定 -->
candidate.First_Name__c = document.forms["refForm"].elements["firstname"].value;
<!-- lastname値を応募者レコードのLast_Name__cへ設定 -->
candidate.Last_Name__c = document.forms["refForm"].elements["lastname"].value;
<!-- phone値を応募者レコードのPhone__cへ設定 -->
candidate.Phone__c = document.forms["refForm"].elements["phone"].value;
<!-- mobile値を応募者レコードのMobile__cへ設定 -->
candidate.Mobile__c = document.forms["refForm"].elements["mobile"].value;
<!-- email値を応募者レコードのEmail__cへ設定 -->
candidate.Email__c = document.forms["refForm"].elements["email"].value;
<!-- Webサービスを呼び出し、応募者レコードを格納している -->
try {
<!-- Apexクラス(WebService): CandidateKeyWebService -->
<!-- 呼び出すメソッド名: submitEmployeeReferral -->
<!-- 渡す引数: 募集職種レコードID -->
<!-- 応募者レコード -->
<!-- 戻り値: 成功→true -->
var success = sforce.apex.execute("CandidateKeyWebService","submitEmployeeReferral",{a:posId,b:candidate});
<!-- 値が返ってきた場合 -->
if (success != null) {
<!-- DB格納成功の場合 -->
if (success == "true") {
<!-- DOMを使ってBODYタグ内を下記 -->
<!-- HTMLに書き換える-->
document.body.innerHTML = "<h1>Referral Successfully Submitted. Thank You!</h1><br/><br/><br/><br/>";
<!-- DB格納失敗の場合 -->
} else {
<!-- DOMを使ってBODYタグ内を下記 -->
<!-- HTMLに書き換える-->
document.body.innerHTML = "<h1>Temporarily unable to submit referrals. Please try again later.</h1><br/><br/><br/><br/>";
}
<!-- SOAP API呼び出し失敗の場合 -->
<!-- デバッグログのトレースをtrueに変更 -->
} else { sforce.debug.trace = true; }
<!-- 例外発生時 -->
} catch(e) {
<!-- デバッグログのトレースをtrueに変更 -->
sforce.debug.trace = true;
<!-- デバッグログに例外情報を書き込む -->
sforce.debug.open();
sforce.debug.log(e);
}
}
</script>
<!-- formタグ相当 -->
<form id="refForm" name="refForm">
<!-- 申込レコードに設定するための既存のオープンされた募集職種 -->
<!-- レコードを選択させるためのテーブル -->
<table ID="Table1">
<tr>
<th colspan="2">Department</th>
<th colspan="2">Open Positions</th>
</tr>
<tr>
<td>Choose:</td>
<td>
<!-- Department欄のリストボックス -->
<!-- 選択状態変更→deptChanged関数呼び出し -->
<!-- 引数には選択ぽうしょんのテキスト値が渡される -->
<select id="deptSelector" type="select-one" size="1" NAME="deptSelector" onchange="javascript:deptChanged(this.options[this.selectedIndex].text);">
<!-- ここは決め打ちリストボックスとして定義されている -->
<option value="none">-- None --</option>
<option value="Engineering">Engineering</option>
<option value="IT">IT</option>
<option value="Finance">Finance</option>
<option value="Support">Support</option>
<option value="Sales">Sales</option>
</select>
</td>
<td>Choose:</td>
<td>
<!-- Open Positions欄のリストボックス -->
<!-- Department欄の値によりオプションが変わる -->
<select id="posSelector" NAME="posSelector" type="select-one" size="1">
<!-- 初期状態ではoptionタグは存在しない -->
</select>
</td>
</tr>
<tr>
<td colspan="4"> <br /></td>
</tr>
<td colspan="1"><h3>Candidate Info:</h3></td>
<td colspan="3"> </td>
<tr>
</tr>
</table>
<!-- 応募者レコードの属性値を入力させるためのテーブル -->
<table id="candidate">
<tr>
<!-- First_Name__cを格納するためのテキストフィールド -->
<td>First Name:</td><td>
<input type="text" id="firstname" /></td>
<!-- Phone__cを格納するためのテキストフィールド -->
<td>Phone:</td>
<td><input type="text" id="phone" /></td>
</tr>
<tr>
<!-- Last_Name__cを格納するためのテキストフィールド -->
<td><font color="#ff2222">Last Name:</font></td>
<td><input type="text" id="lastname" /></td>
<!-- Mobile__cを格納するためのテキストフィールド -->
<td>Mobile:</td>
<td><input type="text" id="mobile" /></td>
</tr>
<tr>
<!-- Email__cを格納するためのテキストフィールド -->
<td><font color="#ff2222">Email:</font></td>
<td><input type="text" id="email" /></td>
<td colspan="2"> </td>
</tr>
<tr>
<!-- レジュメ(ファイル)を格納するためのファイル入力フィールド -->
<!-- ※使用していない※ -->
<td>Resume:</td><td>
<input type="file" id="resume" name="resume" /></td>
<td colspan="2"> </td>
</tr>
<tr>
<td colspan="4"><br /></td>
</tr>
<table cellpadding="0" cellspacing="0" border="0" ID="Table2">
<tr>
<td class="pbTitle"><img src="/s.gif" alt="" width="1" height="1" class="minWidth" title="" /> </td>
<td class="pbButtonb">
<!-- saveボタン:押下→validate()呼び出し -->
<input value=" Save " class="btn" type="button" title="Save" name="save" onclick='javascript:validate();' ID="Button1" />
</td>
</tr>
</table>
</table>
</form>
</apex:page>
このサンプルでは
SOAP APIへ接続するために
Salesforceが用意している
・function.js
・connection.js
・apex.js
を使っている。
これだとWSDLをかませて云々の行程が不要だ。
SOAP APIのほかに
SOQLを文字列加工して実行する方法、
それとDepartment欄が変更された際
即時にForce.com上のDBをアクセスしてとなりの
リストボックス内容を書き換える
なんちゃってAjax(完全非同期ではないので..)の
コードなども読むことが出来る
おいしいつくりになっている。
ご参考まで。
0 件のコメント:
コメントを投稿