Salesforce與網(wǎng)絡(luò)服務(wù)的通信
在Salesforce中可以利用Apex類與遠(yuǎn)程站點(diǎn)的網(wǎng)絡(luò)服務(wù)進(jìn)行通信。當(dāng)遠(yuǎn)程網(wǎng)絡(luò)服務(wù)支持REST方法時(shí),開(kāi)發(fā)者可以利用Apex代碼進(jìn)行數(shù)據(jù)的操作。
設(shè)置遠(yuǎn)程站點(diǎn)
在設(shè)置界面下,搜索“遠(yuǎn)程站點(diǎn)”,點(diǎn)擊“安全性控制”菜單項(xiàng)下的“遠(yuǎn)程站點(diǎn)設(shè)置”鏈接,即可進(jìn)入遠(yuǎn)程站點(diǎn)的一覽表。在此處可以新建、編輯、刪除遠(yuǎn)程站點(diǎn)。這些遠(yuǎn)程站點(diǎn)可以作為網(wǎng)絡(luò)服務(wù)接口。
Apex REST請(qǐng)求
Apex中可以以HttpRequest類為核心和網(wǎng)絡(luò)服務(wù)接口進(jìn)行REST通信。HttpRequest類包括了“setEndpoint()”、“setMethod()”、“setHeader()”、“setBody()”等函數(shù)。
假設(shè)有一個(gè)網(wǎng)絡(luò)服務(wù)接口“https://example.service.com/laguages”,可以對(duì)編程語(yǔ)言的名字進(jìn)行操作。當(dāng)執(zhí)行GET請(qǐng)求時(shí),會(huì)給出一個(gè)json的結(jié)果,包含了一個(gè)“l(fā)anguages”數(shù)組,里面是若干“l(fā)anguage”對(duì)象。
GET請(qǐng)求
用以下代碼可以實(shí)現(xiàn)GET請(qǐng)求:
public class LanguageCallouts {
public static HttpResponse makeGetCallout() {
Http http = new Http();
HttpRequest request = new HttpRequest();
// 設(shè)置網(wǎng)絡(luò)服務(wù)接口的地址
request.setEndpoint('https://example.service.com/laguages');
// 設(shè)置REST方法
request.setMethod('GET');
// 發(fā)送HTTP請(qǐng)求
HttpResponse response = http.send(request);
// 檢查HTTP通信結(jié)果狀態(tài)代碼
if (response.getStatusCode() == 200) {
// 將通信結(jié)果轉(zhuǎn)化為Map類型變量
Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
// 對(duì)結(jié)果進(jìn)行處理,得到language對(duì)象
List<Object> languages = (List<Object>) results.get('languages');
}
return response;
}
}
POST請(qǐng)求
用以下代碼可以實(shí)現(xiàn)POST請(qǐng)求:
public class LanguageCallouts {
public static HttpResponse makePostCallout() {
Http http = new Http();
HttpRequest request = new HttpRequest();
// 設(shè)置網(wǎng)絡(luò)服務(wù)接口的地址
request.setEndpoint('https://example.service.com/laguages');
// 設(shè)置REST方法
request.setMethod('POST');
// 設(shè)置請(qǐng)求的Header,類型為JSON
request.setHeader('Content-Type', 'application/json;charset=UTF-8');
// 將一個(gè)JSON對(duì)象傳入請(qǐng)求的Body,設(shè)置編程語(yǔ)言的名字
request.setBody('{"name":"Apex"}');
// 發(fā)送HTTP請(qǐng)求
HttpResponse response = http.send(request);
// 檢查HTTP通信結(jié)果狀態(tài)代碼
if (response.getStatusCode() == 201) {
// 在控制臺(tái)輸出通信結(jié)果
System.debug(response.getBody());
}
return response;
}
}
對(duì)API請(qǐng)求進(jìn)行單元測(cè)試
在Apex的單元測(cè)試中,如果被測(cè)試的函數(shù)涉及到對(duì)網(wǎng)絡(luò)服務(wù)的請(qǐng)求,則單元測(cè)試函數(shù)無(wú)法真正的連接到網(wǎng)絡(luò)服務(wù)接口進(jìn)行數(shù)據(jù)傳輸。開(kāi)發(fā)者必須建立模擬數(shù)據(jù)。
Apex中提供了“StaticResourceCalloutMock()”函數(shù)和“HttpCalloutMock”接口來(lái)對(duì)網(wǎng)絡(luò)服務(wù)接口的請(qǐng)求結(jié)果進(jìn)行模擬
StaticResourceCalloutMock()函數(shù)
在使用StaticResourceCalloutMock()函數(shù)前需要在系統(tǒng)中建立一個(gè)靜態(tài)資源,其中預(yù)設(shè)了網(wǎng)絡(luò)服務(wù)請(qǐng)求的結(jié)果。
比如要測(cè)試上面示例代碼中的“makeGetCallout()”函數(shù),則首先在系統(tǒng)中建立一個(gè)靜態(tài)資源“mockRequestResult”,其中包含一個(gè)JSON格式的字符串:
{"languages": ["C", "PHP", "Java"]}
在單元測(cè)試函數(shù)中,寫(xiě)入如下代碼:
@isTest
static void testGetCallout() {
StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
// 設(shè)置靜態(tài)資源
mock.setStaticResource('mockRequestResult');
// 設(shè)置模擬網(wǎng)絡(luò)服務(wù)請(qǐng)求的返回結(jié)果
mock.setStatusCode(200);
// 設(shè)置模擬網(wǎng)絡(luò)服務(wù)請(qǐng)求的Header部分
mock.setHeader('Content-Type', 'application/json;charset=UTF-8');
// 設(shè)置模擬的網(wǎng)絡(luò)服務(wù)請(qǐng)求
Test.setMock(HttpCalloutMock.class, mock);
// 運(yùn)行要測(cè)試的函數(shù)
HttpResponse result = LanguageCallouts.makeGetCallout();
// 檢查返回的結(jié)果。該結(jié)果應(yīng)該與mock中設(shè)置的內(nèi)容相同,也包含了靜態(tài)資源里的內(nèi)容
System.assertNotEquals(null, result);
System.assertEquals(200, result.getStatusCode());
System.assertEquals('application/json;charset=UTF-8', result.getHeader('Content-Type'));
Map<String, Object> results = (Map<String, Object>) JSON.deserializedUntyped(result.getBody());
List<Object> languages = (List<Object>) results.get('languages');
System.assertEquals(3, languages.size());
}
HttpCalloutMock接口
HttpCalloutMock接口的使用方法與StaticResourceCalloutMock()函數(shù)類似,不過(guò)不需要先建立靜態(tài)資源,而需要預(yù)先建立一個(gè)全局Apex類,該類實(shí)現(xiàn)了HttpCalloutMock接口,并預(yù)設(shè)了網(wǎng)絡(luò)服務(wù)請(qǐng)求的模擬數(shù)據(jù)。
比如要測(cè)試上面示例代碼中的“makePostCallout()”函數(shù),則首先在系統(tǒng)中建立一個(gè)“LanguagesHttpCalloutMock”類,在其中設(shè)置:
@isTest
global class LanguagesHttpCalloutMock implements HttpCalloutMOck {
global HttpResponse response(HttpRequest request) {
HttpResponse response = new HttpResponse();
response.setHeader('Content-Type', 'application/json');
response.setBody('{"languages": ["C", "PHP", "Java", "Apex"]}');
response.setStatusCode(200);
return response;
}
}
在單元測(cè)試函數(shù)中,寫(xiě)入如下代碼:
@isTest
static void testPostCallout() {
// 設(shè)置模擬的網(wǎng)絡(luò)服務(wù)請(qǐng)求
Test.setMock(HttpCalloutMock.class, new LanguagesHttpCalloutMock());
// 運(yùn)行要測(cè)試的函數(shù)
HttpResponse result = LanguageCallouts.makePostCallout();
// 檢查返回的結(jié)果
System.assertEquals(200, result.getStatusCode());
System.assertEquals('application/json;charset=UTF-8', result.getHeader('Content-Type'));
String expectedResult = '{"languages": ["C", "PHP", "Java", "Apex"]}';
System.assertEquals(response.getBody(), expectedResult);
}
Apex類作為網(wǎng)絡(luò)服務(wù)
Apex類可以被擴(kuò)展為網(wǎng)絡(luò)服務(wù),外部的請(qǐng)求可以通過(guò)此類來(lái)與Salesforce中的數(shù)據(jù)進(jìn)行通信。
將Apex類定義為REST服務(wù)類
將Apex類定義為REST服務(wù)類只需要以下步驟:
- 將類定義為全局類
- 將特定注解添加到類和函數(shù)的定義
比如:
@RestResource(urlMapping='/Account/*)
global with sharing class ExampleRestClass {
@HttpGet
global static Account getAccount() {
// ...
}
}
代碼講解:
- 在類的定義上方,添加了@RestResource注解,并定義了“urlMapping”屬性。這樣,該Salesforce中的特定URL便可以作為REST服務(wù)的端點(diǎn)。在此示例中,外部請(qǐng)求通過(guò)URL “https://xxx.salesforce.com/services/apexrest/Account/” 就可以調(diào)用此類。需要注意的是,“urlMapping”屬性是區(qū)分大小寫(xiě)的。
- 在函數(shù)的上方,添加了@HttpGet注解,說(shuō)明此類相應(yīng)“GET”方法。同樣,基于標(biāo)準(zhǔn)的REST方法,還有其他注解:@HttpPost, @HttpDelete, @HttpPut, @HttpPatch等。
將Apex類定義為SOAP服務(wù)類
將Apex類定義為SOAP服務(wù)類和定義為REST服務(wù)類的步驟類似,只不過(guò)不需要注解,而是直接用“webservice”關(guān)鍵字定義函數(shù)。比如:
global with sharing class ExampleSoapClass {
webservice static Account getAccount(String Id) {
// ...
}
}
從設(shè)置界面的“Apex 類”鏈接進(jìn)入Apex類一覽表,再進(jìn)入該類的詳細(xì)信息頁(yè)面,即可下載該類對(duì)應(yīng)的WSDL文件,用于SOAP請(qǐng)求。