Аннотация: В этом руководстве приведен пример JSP и его интеграция с REST API Salesforce. Мы пройдем через пошаговый процесс создания внешнего клиента для управления вашими данными с помощью Force.com , используя HTTP (S) и JSON.
В этом примере я использую Mac OS X 10.9.2 с сервером Apache Tomcat 7 и Java 1.7. Eclipse Java EE edition — это среда разработки, используемая для разработки и тестирования. Инструкции, приведенные в этом руководстве, должны работать с небольшими изменениями и для других платформ.
Если вы хотите получить доступ ко всему примеру кода из этого учебника, вы можете получить к нему доступ здесь: github.com/seethaa/force_rest_example
Весь код обновлен для работы с библиотеками httpclient 4.3.
Что такое ОТДЫХ?
REST расшифровывается как Re Presenalal S tate T transfer и представляет собой протокол связи клиент-сервер без сохранения состояния по HTTP.
Почему и когда использовать API REST в Java для вашей JSP
REST API хорошо подходит для браузерных приложений, которые требуют большого взаимодействия, и использует синхронную связь для передачи данных. Salesforce REST API предоставляет интерфейс программирования для простых веб-сервисов для взаимодействия с Force.com и поддерживает форматы XML и JSON. Salesforce REST API хорошо работает для мобильных приложений или динамических веб-сайтов, чтобы быстро получать или обновлять записи на вашем веб-сервере. В то время как массовый поиск записей должен быть зарезервирован для BulkAPI , этот упрощенный REST API может использоваться для общих серверных страниц, которые включают быстрые обновления и частые взаимодействия с пользователем, например, обновление одной пользовательской записи.
Настройка учетной записи и предварительных условий
Вам понадобится следующее:
- Перейдите на https://developer.salesforce.com/signup и зарегистрируйте свой бесплатный аккаунт DE. В этом примере я рекомендую подписаться на Developer Edition, даже если у вас уже есть учетная запись. Это гарантирует, что вы получите чистую среду с последними включенными функциями.
- Сервер приложений Java. Я создал мой, используя Apache Tomcat 7 на Mac OS X и Eclipse в качестве IDE. Существует также бесплатный плагин Eclipse по адресу http://developer.salesforce.com/page/Force.com_IDE, но в этом руководстве использовалась оригинальная настройка Eclipse.
- Настройте SSL на своем сервере Tomcat, используя http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html . Если вы разрабатываете в Eclipse, обязательно добавьте фрагмент Connector в файл server.xml в вашей среде Eclipse, например:
1
<
Connector
SSLEnabled
=
"true"
clientAuth
=
"false"
keystoreFile
=
"/Users/seetha/.keystore"
keystorePass
=
"password"
maxThreads
=
"200"
port
=
"8443"
protocol
=
"HTTP/1.1"
scheme
=
"https"
secure
=
"true"
sslProtocol
=
"TLS"
/>
- Добавьте необходимые файлы JAR в WebContent / WEBINF / lib. Вам понадобятся commons-codec-1.6.jar , httpclient4.3.3.jar , httpcore-4.3.2.jar , commons-logging-1.1.3.jar и java-json.jar . Для Eclipse мне также нужно было убедиться, что все jar-файлы были добавлены в путь сборки (щелкните правой кнопкой мыши Project> Build Path → Configure path build → Выберите вкладку Libraries → Выберите Add Jars → Выберите файлы Jar из папки WEBINF / lib.
Создать подключенное приложение
- Вернувшись в свой Force.com DE, создайте новое подключенное приложение через консоль. Нажмите Настройка → Сборка → Создать → Приложения. Прокрутите страницу вниз до раздела «Подключенные приложения» и нажмите кнопку «Создать».
- Убедитесь, что URL-адрес обратного вызова — http: // localhost: 8080 / <your_app_context_path> / oauth / _callback
(Вы можете найти путь к контексту приложения, вернувшись к Eclipse: щелкните правой кнопкой мыши на Project → Свойства → Настройки веб-проекта → Корень контекста)
- Установите флажок «Включить настройки OAuth»
- Обязательными областями OAuth для этого руководства (см. Рис. 1) являются «Доступ и управление вашими данными (api)» и «Предоставление доступа к вашим данным через Интернет (web)», но эти области следует изменить в соответствии с вашими требованиями.
- Сохранить
- Убедитесь, что URL-адрес обратного вызова — http: // localhost: 8080 / <your_app_context_path> / oauth / _callback
- Скопируйте ClientID и Client Secret (см. Рисунок 2), потому что оба они будут использованы на следующем шаге.
Аутентификация
Ниже приведены три файла, которые необходимо импортировать в ваш проект JSP:
index.html
01020304050607080910111213141516<!
DOCTYPE
html PUBLIC "//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<
html
>
<
head
>
<
meta
http
equiv
=
"ContentType"
content
=
"text/html; charset=UTF8"
>
<
title
>REST/OAuth Example</
title
>
</
head
>
<
body
>
<
script
type
=
"text/javascript"
language
=
"javascript"
>
if (location.protocol != "https:") {
document.write("OAuth will not work correctly from plain http. "+ "Please use an https URL.");
} else {
document.write("<
a
href=\"oauth\">Run Connected App demo via REST/OAuth.</
a
>");
}
</
script
>
</
body
>
</
html
>
OAuthConnectedApp.java
001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151import
java.io.IOException;
import
java.io.InputStream;
import
java.io.UnsupportedEncodingException;
import
java.net.URLEncoder;
import
java.util.ArrayList;
import
java.util.List;
import
javax.servlet.ServletException;
import
javax.servlet.annotation.WebInitParam;
import
javax.servlet.annotation.WebServlet;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.apache.http.Consts;
import
org.apache.http.HttpEntity;
import
org.apache.http.NameValuePair;
import
org.apache.http.client.entity.UrlEncodedFormEntity;
import
org.apache.http.client.methods.CloseableHttpResponse;
import
org.apache.http.client.methods.HttpPost;
import
org.apache.http.impl.client.CloseableHttpClient;
import
org.apache.http.impl.client.HttpClients;
import
org.apache.http.message.BasicNameValuePair;
import
org.json.JSONException;
import
org.json.JSONObject;
import
org.json.JSONTokener;
@WebServlet
(name =
"oauth"
, urlPatterns = {
"/oauth/*"
,
"/oauth"
}, initParams = {
// clientId is 'Consumer Key' in the Remote Access UI
//**Update with your own Client ID
@WebInitParam
(name =
"clientId"
, value =
"3MVG9JZ_r.QzrS7jzujCYrebr8kajDEcjXQLXnV9nGU6PaxOjuOi_n8EcUf0Ix9qqk1lYCa4_Jaq7mpqxi2YT"
),
// clientSecret is 'Consumer Secret' in the Remote Access UI
//**Update with your own Client Secret
@WebInitParam
(name =
"clientSecret"
, value =
"2307033558641049067"
),
// This must be identical to 'Callback URL' in the Remote Access UI
//**Update with your own URI
@WebInitParam
(name =
"redirectUri"
, value =
"http://localhost:8080/force_rest_example/oauth/_callback"
),
/**
* Servlet parameters
*
@author
seetha
*
*/
public
class
OAuthConnectedApp
extends
HttpServlet {
private
static
final
long
serialVersionUID = 1L;
private
static
final
String ACCESS_TOKEN =
"ACCESS_TOKEN"
;
private
static
final
String INSTANCE_URL =
"INSTANCE_URL"
;
private
String clientId =
null
;
private
String clientSecret =
null
;
private
String redirectUri =
null
;
private
String environment =
null
;
private
String authUrl =
null
;
private
String tokenUrl =
null
;
public
void
init()
throws
ServletException {
clientId =
this
.getInitParameter(
"clientId"
);
clientSecret =
this
.getInitParameter(
"clientSecret"
);
redirectUri =
this
.getInitParameter(
"redirectUri"
);
environment =
this
.getInitParameter(
"environment"
);
try
{
authUrl = environment
+
"/services/oauth2/authorize?response_type=code&client_id="
+ clientId +
"&redirect_uri="
+ URLEncoder.encode(redirectUri,
"UTF8"
);
}
catch
(UnsupportedEncodingException e) {
throw
new
ServletException(e);
}
tokenUrl = environment +
"/services/oauth2/token"
;
}
protected
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
String accessToken = (String) request.getSession().getAttribute(ACCESS_TOKEN);
//System.out.println("calling doget");
if
(accessToken ==
null
) {
String instanceUrl =
null
;
if
(request.getRequestURI().endsWith(
"oauth"
)) {
// we need to send the user to authorize
response.sendRedirect(authUrl);
return
;
}
else
{
System.out.println(
"Auth successful got callback"
);
String code = request.getParameter(
"code"
);
// Create an instance of HttpClient.
CloseableHttpClient httpclient = HttpClients.createDefault();
try
{
// Create an instance of HttpPost.
HttpPost httpost =
new
HttpPost(tokenUrl);
// Adding all form parameters in a List of type NameValuePair
List<NameValuePair> nvps =
new
ArrayList<NameValuePair>();
nvps.add(
new
BasicNameValuePair(
"code"
, code));
nvps.add(
new
BasicNameValuePair(
"grant_type"
,
"authorization_code"
));
nvps.add(
new
BasicNameValuePair(
"client_id"
, clientId));
nvps.add(
new
BasicNameValuePair(
"client_secret"
, clientSecret));
nvps.add(
new
BasicNameValuePair(
"redirect_uri"
, redirectUri));
httpost.setEntity(
new
UrlEncodedFormEntity(nvps, Consts.UTF_8));
// Execute the request.
CloseableHttpResponse closeableresponse=httpclient.execute(httpost);
System.out.println(
"Response Statusline:"
+closeableresponse.getStatusLine());
try
{
// Do the needful with entity.
HttpEntity entity = closeableresponse.getEntity();
InputStream rstream = entity.getContent();
JSONObject authResponse =
new
JSONObject(
new
JSONTokener(rstream));
accessToken = authResponse.getString(
"access_token"
);
instanceUrl = authResponse.getString(
"instance_url"
);
}
catch
(JSONException e) {
// TODO Autogenerated catch block e.printStackTrace();
e.printStackTrace();
}
finally
{
// Closing the response
closeableresponse.close();
}
}
finally
{
httpclient.close();
}
}
// Set a session attribute so that other servlets can get the access token
request.getSession().setAttribute(ACCESS_TOKEN, accessToken);
// We also get the instance URL from the OAuth response, so set it in the session too
request.getSession().setAttribute(INSTANCE_URL, instanceUrl);
}
response.sendRedirect(request.getContextPath() +
"/ConnectedAppREST"
);
}
}
ConnectedAppREST.java
001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314import
java.io.IOException;
import
java.io.InputStream;
import
java.io.PrintWriter;
import
java.net.URISyntaxException;
import
java.util.Iterator;
import
javax.servlet.ServletException;
import
javax.servlet.annotation.WebServlet;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.apache.http.HttpEntity;
import
org.apache.http.HttpStatus;
import
org.apache.http.client.methods.CloseableHttpResponse;
import
org.apache.http.client.methods.HttpDelete;
import
org.apache.http.client.methods.HttpGet;
import
org.apache.http.client.methods.HttpPost;
import
org.apache.http.client.utils.URIBuilder;
import
org.apache.http.entity.ContentType;
import
org.apache.http.entity.StringEntity;
import
org.apache.http.impl.client.CloseableHttpClient;
import
org.apache.http.impl.client.HttpClients;
import
org.json.JSONArray;
import
org.json.JSONException;
import
org.json.JSONObject;
import
org.json.JSONTokener;
@WebServlet
(urlPatterns = {
"/ConnectedAppREST"
})
/**
* Demo for Connect App/REST API
* @author seetha
*
*/
public
class
ConnectedAppREST
extends
HttpServlet {
private
static
final
long
serialVersionUID = 1L;
private
static
final
String ACCESS_TOKEN =
"ACCESS_TOKEN"
;
private
static
final
String INSTANCE_URL =
"INSTANCE_URL"
;
private
void
showAccounts(String instanceUrl, String accessToken,
PrintWriter writer)
throws
ServletException, IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet =
new
HttpGet();
//add key and value
httpGet.addHeader(
"Authorization"
,
"OAuth "
+ accessToken);
try
{
URIBuilder builder =
new
URIBuilder(instanceUrl+
"/services/data/v30.0/query"
);
builder.setParameter(
"q"
,
"SELECT Name, Id from Account LIMIT 100"
);
httpGet.setURI(builder.build());
CloseableHttpResponse closeableresponse = httpclient.execute(httpGet);
System.out.println(
"Response Status line :"
+ closeableresponse.getStatusLine());
if
(closeableresponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
// Now lets use the standard java json classes to work with the results
try
{
// Do the needful with entity.
HttpEntity entity = closeableresponse.getEntity();
InputStream rstream = entity.getContent();
JSONObject authResponse =
new
JSONObject(
new
JSONTokener(rstream));
System.out.println(
"Query response: "
+ authResponse.toString(
2
));
writer.write(authResponse.getInt(
"totalSize"
) +
" record(s) returned\n\n"
);
JSONArray results = authResponse.getJSONArray(
"records"
);
for
(
int
i =
0
; i < results.length(); i++) {
writer.write(results.getJSONObject(i).getString(
"Id"
)
+
", "
+ results.getJSONObject(i).getString(
"Name"
)
+
"\n"
);
}
writer.write(
"\n"
);
}
catch
(JSONException e) {
e.printStackTrace();
throw
new
ServletException(e);
}
}
}
catch
(URISyntaxException e1) {
// TODO Autogenerated catch block
e1.printStackTrace();
}
finally
{
httpclient.close();
}
}
private
String createAccount(String name, String instanceUrl,
String accessToken, PrintWriter writer)
throws
ServletException, IOException {
String accountId =
null
;
CloseableHttpClient httpclient = HttpClients.createDefault();
JSONObject account =
new
JSONObject();
try
{
account.put(
"Name"
, name);
}
catch
(JSONException e) {
e.printStackTrace();
throw
new
ServletException(e);
}
HttpPost httpost =
new
HttpPost(instanceUrl+
"/services/data/v30.0/sobjects/Account/"
);
httpost.addHeader(
"Authorization"
,
"OAuth "
+ accessToken);
StringEntity messageEntity =
new
StringEntity( account.toString(), ContentType.create(
"application/json"
));
httpost.setEntity(messageEntity);
// Execute the request.
CloseableHttpResponse closeableresponse = httpclient.execute(httpost);
System.out.println(
"Response Status line :"
+ closeableresponse.getStatusLine());
try
{
writer.write(
"HTTP status "
+ closeableresponse.getStatusLine().getStatusCode() +
" creating account\n\n"
);
if
(closeableresponse.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) {
try
{
// Do the needful with entity.
HttpEntity entity = closeableresponse.getEntity();
InputStream rstream = entity.getContent();
JSONObject authResponse =
new
JSONObject(
new
JSONTokener(rstream));
System.out.println(
"Create response: "
+ authResponse.toString(
2
));
if
(authResponse.getBoolean(
"success"
)) {
accountId = authResponse.getString(
"id"
);
writer.write(
"New record id "
+ accountId +
"\n\n"
);
}
}
catch
(JSONException e) {
e.printStackTrace();
// throw new ServletException(e);
}
}
}
finally
{
httpclient.close();
}
return
accountId;
}
private
void
showAccount(String accountId, String instanceUrl,
String accessToken, PrintWriter writer)
throws
ServletException, IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet =
new
HttpGet();
//add key and value
httpGet.addHeader(
"Authorization"
,
"OAuth "
+ accessToken);
try
{
URIBuilder builder =
new
URIBuilder(instanceUrl +
"/services/data/v30.0/sobjects/Account/"
+ accountId);
httpGet.setURI(builder.build());
//httpclient.execute(httpGet);
CloseableHttpResponse closeableresponse = httpclient.execute(httpGet);
System.out.println(
"Response Status line :"
+ closeableresponse.getStatusLine());
if
(closeableresponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
try
{
// Do the needful with entity.
HttpEntity entity = closeableresponse.getEntity();
InputStream rstream = entity.getContent();
JSONObject authResponse =
new
JSONObject(
new
JSONTokener(rstream));
System.out.println(
"Query response: "
+ authResponse.toString(
2
));
writer.write(
"Account content\n\n"
);
Iterator iterator = authResponse.keys();
while
(iterator.hasNext()) {
String key = (String) iterator.next();
Object obj = authResponse.get(key);
String value =
null
;
if
(obj
instanceof
String) {
value = (String) obj;
}
writer.write(key +
":"
+ (value !=
null
? value :
""
) +
"\n"
);
}
writer.write(
"\n"
);
}
catch
(JSONException e) {
e.printStackTrace();
throw
new
ServletException(e);
}
}
}
catch
(URISyntaxException e1) {
// TODO Autogenerated catch block
e1.printStackTrace();
}
finally
{
httpclient.close();
}
}
private
void
updateAccount(String accountId, String newName, String city, String instanceUrl, String accessToken, PrintWriter writer)
throws
ServletException, IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
JSONObject update =
new
JSONObject();
try
{
update.put(
"Name"
, newName);
update.put(
"BillingCity"
, city);
}
catch
(JSONException e) {
e.printStackTrace();
throw
new
ServletException(e);
}
HttpPost httpost =
new
HttpPost(instanceUrl +
"/services/data/v30.0/sobjects/Account/"
+accountId+
"?_HttpMethod=PATCH"
);
httpost.addHeader(
"Authorization"
,
"OAuth "
+ accessToken);
StringEntity messageEntity =
new
StringEntity( update.toString(), ContentType.create(
"application/json"
));
httpost.setEntity(messageEntity);
// Execute the request.
CloseableHttpResponse closeableresponse = httpclient.execute(httpost); System.out.println(
"Response Status line :"
+ closeableresponse.getStatusLine());
try
{
writer.write(
"HTTP status "
+ closeableresponse.getStatusLine().getStatusCode() +
" updating account "
+ accountId +
"\n\n"
);
}
finally
{
httpclient.close();
}
}
private
void
deleteAccount(String accountId, String instanceUrl, String accessToken, PrintWriter writer)
throws
IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpDelete delete =
new
HttpDelete(instanceUrl +
"/services/data/v30.0/sobjects/Account/"
+ accountId);
delete.setHeader(
"Authorization"
,
"OAuth "
+ accessToken);
// Execute the request.
CloseableHttpResponse closeableresponse = httpclient.execute(delete);
System.out.println(
"Response Status line :"
+ closeableresponse.getStatusLine());
try
{
writer.write(
"HTTP status "
+ closeableresponse.getStatusLine().getStatusCode() +
" deleting account "
+ accountId +
"\n\n"
);
}
finally
{
delete.releaseConnection();
}
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
PrintWriter writer = response.getWriter();
String accessToken = (String) request.getSession().getAttribute( ACCESS_TOKEN);
String instanceUrl = (String) request.getSession().getAttribute( INSTANCE_URL);
if
(accessToken ==
null
) {
writer.write(
"Error no access token"
);
return
;
}
writer.write(
"We have an access token: "
+ accessToken +
"\n"
+
"Using instance "
+ instanceUrl +
"\n\n"
);
showAccounts(instanceUrl, accessToken, writer);
String accountId = createAccount(
"My New Org"
, instanceUrl, accessToken, writer);
if
(accountId ==
null
) {
System.out.println(
"Account ID null"
);
}
showAccount(accountId, instanceUrl, accessToken, writer);
showAccounts(instanceUrl, accessToken, writer);
updateAccount(accountId,
"My New Org, Inc"
,
"San Francisco"
, instanceUrl, accessToken, writer);
showAccount(accountId, instanceUrl, accessToken, writer);
deleteAccount(accountId, instanceUrl, accessToken, writer);
showAccounts(instanceUrl, accessToken, writer);
}
}
- Измените OAuthConnectedApp.java, чтобы заменить поля Client ID, Client Secret и URI обратного вызова на основе конфигурации подключенного приложения.
- Запустите сервер Tomcat в Eclipse (см. Рисунок 3) или извне и перейдите по адресу https: // localhost: 8443 / <your_app_context_path> /
- Нажатие на ссылку выше (см. Рисунок 4) не будет работать, если только через HTTPS, а SSL должен быть настроен как конечная точка для Tomcat.
Если все настройки выполнены правильно, вы должны увидеть экран входа в систему salesforce.com (см. Рисунок 5). Идите вперед и войдите с учетными данными salesforce.com, чтобы авторизовать ваше веб-приложение для доступа к ресурсам.
- Вход в систему позволит демонстрационной версии ConnectedAppREST выполнять методы для создания, отображения, обновления и удаления записей (см. Рисунок 6).
* Советы и предупреждения
- Убедитесь, что у вас есть учетная запись Developer Edition (DE), потому что между Professional, Enterprise, Developer и т. Д. Есть небольшие различия. Редакция Developer бесплатна и не имеет срока действия (если не используется через год).
- URL-адрес обратного вызова в OAuthConnectedApp.java должен совпадать с URL-адресом, добавленным в подключенное приложение.
- Если вы получаете ошибку HTTP 403, это означает, что запрашиваемый вами ресурс «Запрещен» от доступа. Убедитесь, что имя пользователя / учетная запись, к которой вы обращаетесь, имеет соответствующие разрешения.
- Убедитесь, что index.html находится непосредственно в каталоге WebContent.
Ресурсы
Для полного набора или ресурсов, проверьте: http://developer.salesforce.com/en/mobile/resources