摘要:本教程提供了一个JSP示例以及如何将其与Salesforce REST API集成。 我们将逐步完成创建外部客户端以使用Force.com (同时使用HTTP(S)和JSON)管理您的数据的分步过程。
在此示例中,我将Mac OS X 10.9.2与Apache Tomcat 7服务器和Java 1.7一起使用。 Eclipse Java EE版是用于开发和测试的IDE。 本教程中给出的说明也应适用于其他平台的较小修改。
如果要访问本教程中的整个示例代码,则可以在以下位置访问它: github.com/seethaa/force_rest_example
所有代码已更新为可与httpclient 4.3库一起使用。
什么是REST?
REST代表再表象小号泰特贸易交接,并且是无状态的客户端-服务器通信协议通过HTTP。
为什么以及何时在Java中为JSP使用REST API
REST API非常适合需要大量交互并使用同步通信来传输数据的浏览器应用程序。 Salesforce REST API为简单的Web服务提供了与Force.com进行交互的编程接口,并支持XML和JSON格式。 Salesforce REST API非常适合移动应用程序或动态网站,以在Web服务器上快速检索或更新记录。 虽然应为BulkAPI保留批量记录检索,但此轻量级的REST API可以用于常见服务器页面,这些页面涉及快速更新和频繁的用户交互,例如更新单个用户记录。
设置您的开发帐户和前提条件
您将需要以下内容:
- 转到https://developer.salesforce.com/signup并注册您的免费DE帐户。 就本示例而言,即使您已经有一个帐户,我也建议注册一个Developer Edition。 这样可以确保您在启用了最新功能的情况下获得干净的环境。
- Java应用程序服务器。 我在Mac OS X和Eclipse上使用Apache Tomcat 7作为IDE创建了我的数据库。 http://developer.salesforce.com/page/Force.com_IDE上还有一个免费的Eclipse插件,但本教程使用了原始的Eclipse设置。
- 使用http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html在Tomcat服务器上配置SSL。 如果您在Eclipse中进行开发,请确保在Eclipse环境中的server.xml文件中添加连接器部分,例如:
- 将所需的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→配置构建路径→选择Libraries选项卡→单击Add Jars→从WEBINF / lib文件夹中选择Jar文件。
创建一个连接的应用程序
- 返回Force.com DE,通过控制台创建一个新的Connected App。 单击设置→构建→创建→应用程序。 向下滚动到“已连接的应用程序”部分,然后单击“新建”按钮。
- 确保回调URL为http:// localhost:8080 /
/ oauth / _callback (您可以通过返回Eclipse找到应用程序上下文路径:右键单击Project→Properties→Web Project Settings→Context root)
- 选中“启用OAuth设置”复选框
- 本教程所需的OAuth范围(请参见图1)是“访问和管理数据(api)”和“通过Web提供对数据的访问”(web),但是应根据您的要求更改这些范围。
- 救
- 确保回调URL为http:// localhost:8080 /
- 复制ClientID和Client Secret(参见图2),因为这两个都将在下一步中使用。
认证方式
需要将三个文件导入到您的JSP项目中,如下所示:
index.html
REST/OAuth Example OAuthConnectedApp.java
import 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"), @WebInitParam(name = "environment", value = "https://login.salesforce.com"), }) /** * 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
nvps = new ArrayList (); 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
import 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以基于Connected App配置替换Client ID,Client Secret和Callback URI字段。
- 在Eclipse(请参见图3)中或从外部启动Tomcat服务器,并导航到https:// localhost:8443 /
/
- 除非通过HTTPS,否则单击上面的链接(请参见图4)将不起作用,并且必须将SSL配置为Tomcat的端点。
如果所有配置都正确完成,您应该会看到一个salesforce.com登录屏幕(请参见图5)。 继续并使用salesforce.com凭据登录以授权Web应用程序访问资源。
- 登录将允许ConnectedAppREST演示执行创建,显示,更新和删除记录的方法(请参见图6)。
*提示和警告
- 确保您拥有一个Developer Edition(DE)帐户,因为Professional,Enterprise,Developer等之间存在细微差别。Developer版本是免费的,并且不会过期(除非一年后未使用)。
- OAuthConnectedApp.java中的回调URL必须与添加到连接的应用程序的URL相同。
- 如果收到HTTP 403错误,则表示正在访问您请求的资源“被禁止”。 检查您用来访问的用户名/帐户是否具有适当的权限。
- 确保index.html直接在WebContent目录下。
资源资源
有关全面的设置或资源,请访问: http : //developer.salesforce.com/en/mobile/resources
参考文献
- Force.com REST API开发人员指南 (PDF)
- 使用Force.com REST API
翻译自: https://www.javacodegeeks.com/2014/06/how-to-use-salesforce-rest-api-with-your-javaserver-pages.html