Аннотация: В этом руководстве приведен пример 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<ConnectorSSLEnabled="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<!DOCTYPEhtml PUBLIC "//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><metahttpequiv="ContentType"content="text/html; charset=UTF8"><title>REST/OAuth Example</title></head><body><scripttype="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("<ahref=\"oauth\">Run Connected App demo via REST/OAuth.</a>");}</script></body></html>OAuthConnectedApp.java 001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151importjava.io.IOException;importjava.io.InputStream;importjava.io.UnsupportedEncodingException;importjava.net.URLEncoder;importjava.util.ArrayList;importjava.util.List;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebInitParam;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.apache.http.Consts;importorg.apache.http.HttpEntity;importorg.apache.http.NameValuePair;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpPost;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.apache.http.message.BasicNameValuePair;importorg.json.JSONException;importorg.json.JSONObject;importorg.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*@authorseetha**/publicclassOAuthConnectedAppextendsHttpServlet {privatestaticfinallongserialVersionUID = 1L;privatestaticfinalString ACCESS_TOKEN ="ACCESS_TOKEN";privatestaticfinalString INSTANCE_URL ="INSTANCE_URL";privateString clientId =null;privateString clientSecret =null;privateString redirectUri =null;privateString environment =null;privateString authUrl =null;privateString tokenUrl =null;publicvoidinit()throwsServletException {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) {thrownewServletException(e);}tokenUrl = environment +"/services/oauth2/token";}protectedvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, 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 authorizeresponse.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 =newHttpPost(tokenUrl);// Adding all form parameters in a List of type NameValuePairList<NameValuePair> nvps =newArrayList<NameValuePair>();nvps.add(newBasicNameValuePair("code", code));nvps.add(newBasicNameValuePair("grant_type","authorization_code"));nvps.add(newBasicNameValuePair("client_id", clientId));nvps.add(newBasicNameValuePair("client_secret", clientSecret));nvps.add(newBasicNameValuePair("redirect_uri", redirectUri));httpost.setEntity(newUrlEncodedFormEntity(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 =newJSONObject(newJSONTokener(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 responsecloseableresponse.close();}}finally{httpclient.close();}}// Set a session attribute so that other servlets can get the access tokenrequest.getSession().setAttribute(ACCESS_TOKEN, accessToken);// We also get the instance URL from the OAuth response, so set it in the session toorequest.getSession().setAttribute(INSTANCE_URL, instanceUrl);}response.sendRedirect(request.getContextPath() +"/ConnectedAppREST");}}ConnectedAppREST.java 001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314importjava.io.IOException;importjava.io.InputStream;importjava.io.PrintWriter;importjava.net.URISyntaxException;importjava.util.Iterator;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.apache.http.HttpEntity;importorg.apache.http.HttpStatus;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpDelete;importorg.apache.http.client.methods.HttpGet;importorg.apache.http.client.methods.HttpPost;importorg.apache.http.client.utils.URIBuilder;importorg.apache.http.entity.ContentType;importorg.apache.http.entity.StringEntity;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.json.JSONArray;importorg.json.JSONException;importorg.json.JSONObject;importorg.json.JSONTokener;@WebServlet(urlPatterns = {"/ConnectedAppREST"})/*** Demo for Connect App/REST API* @author seetha**/publicclassConnectedAppRESTextendsHttpServlet {privatestaticfinallongserialVersionUID = 1L;privatestaticfinalString ACCESS_TOKEN ="ACCESS_TOKEN";privatestaticfinalString INSTANCE_URL ="INSTANCE_URL";privatevoidshowAccounts(String instanceUrl, String accessToken,PrintWriter writer)throwsServletException, IOException {CloseableHttpClient httpclient = HttpClients.createDefault();HttpGet httpGet =newHttpGet();//add key and valuehttpGet.addHeader("Authorization","OAuth "+ accessToken);try{URIBuilder builder =newURIBuilder(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 resultstry{// Do the needful with entity.HttpEntity entity = closeableresponse.getEntity();InputStream rstream = entity.getContent();JSONObject authResponse =newJSONObject(newJSONTokener(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(inti =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();thrownewServletException(e);}}}catch(URISyntaxException e1) {// TODO Autogenerated catch blocke1.printStackTrace();}finally{httpclient.close();}}privateString createAccount(String name, String instanceUrl,String accessToken, PrintWriter writer)throwsServletException, IOException {String accountId =null;CloseableHttpClient httpclient = HttpClients.createDefault();JSONObject account =newJSONObject();try{account.put("Name", name);}catch(JSONException e) {e.printStackTrace();thrownewServletException(e);}HttpPost httpost =newHttpPost(instanceUrl+"/services/data/v30.0/sobjects/Account/");httpost.addHeader("Authorization","OAuth "+ accessToken);StringEntity messageEntity =newStringEntity( 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 =newJSONObject(newJSONTokener(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();}returnaccountId;}privatevoidshowAccount(String accountId, String instanceUrl,String accessToken, PrintWriter writer)throwsServletException, IOException {CloseableHttpClient httpclient = HttpClients.createDefault();HttpGet httpGet =newHttpGet();//add key and valuehttpGet.addHeader("Authorization","OAuth "+ accessToken);try{URIBuilder builder =newURIBuilder(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 =newJSONObject(newJSONTokener(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(objinstanceofString) {value = (String) obj;}writer.write(key +":"+ (value !=null? value :"") +"\n");}writer.write("\n");}catch(JSONException e) {e.printStackTrace();thrownewServletException(e);}}}catch(URISyntaxException e1) {// TODO Autogenerated catch blocke1.printStackTrace();}finally{httpclient.close();}}privatevoidupdateAccount(String accountId, String newName, String city, String instanceUrl, String accessToken, PrintWriter writer)throwsServletException, IOException {CloseableHttpClient httpclient = HttpClients.createDefault();JSONObject update =newJSONObject();try{update.put("Name", newName);update.put("BillingCity", city);}catch(JSONException e) {e.printStackTrace();thrownewServletException(e);}HttpPost httpost =newHttpPost(instanceUrl +"/services/data/v30.0/sobjects/Account/"+accountId+"?_HttpMethod=PATCH");httpost.addHeader("Authorization","OAuth "+ accessToken);StringEntity messageEntity =newStringEntity( 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();}}privatevoiddeleteAccount(String accountId, String instanceUrl, String accessToken, PrintWriter writer)throwsIOException {CloseableHttpClient httpclient = HttpClients.createDefault();HttpDelete delete =newHttpDelete(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)*/@OverrideprotectedvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, 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





