看了看自己前一篇博客还是去年12月份的,看来已经大半年没写博客了。一方面是太忙了,但最重要的还是懒得写了(想想之前还是一周保持两篇的更新速度)。借这次五一长假调查salesforce的web service功能就开启今年的第一篇博客吧!

背景

在Salesforce中可以创建Web Service供外部系统调用,并且可以以SOAP或者REST方式向外提供调用接口,下来的内容将详细讲述一下用SOAP的方式创建Web Service并且用java的程序进行简单的调用。
在查看网上的多片博客后终于实现。下面记录一下过程。

【注:如果要使用salesforce中的自定义的Apex Class时,要想使其成为web service,那么class一定要定义成global的,具体的方法要用 webService static 修饰】

1):在Salesforce中创建如下Class,例如:

global class SFAccountWebService {
    
    webService static string UpsertAccount(String accountXmlInfo) {
        Account currentAcc = GenerateAccountFromXmlInfo(accountXmlInfo);
        try
        {
            Account acc = [Select Id From Account a Where AccountNumber =: currentAcc.AccountNumber];
            if(acc != null){
                currentAcc.Id = acc.Id;
            }
            upsert currentAcc;
            return 'true';
        }
        catch(exception ex){
            return 'false';    
        }
    }
    
    
    private static Account GenerateAccountFromXmlInfo(String accountXmlInfo){
        Account currentAcc = new Account();
        // Parse the xml info to generate the Account Object
        return currentAcc;
    }
    
}

2):在保存好上述的class之后,我们到setup --> build --> develop --> apex classes 中找到刚刚保存的class,我们会发现在对应的Action中有WSDL这个选项,此选项就是Salesforce默认所提供的将Web Service的class转化成WSDL文件。如下图所示

java成熟saas框架 java saas_jar


3):点击上图的WSDL按钮,会看到如下界面,这里显示的是生成的WSDL文件的详细信息,我们点击鼠标右键,将此文件保存到本地,这里姑且取名为SFAccountWebService.wsdl

java成熟saas框架 java saas_java成熟saas框架_02


接下来就是将SFAccountWebService.wsdl生成对应的SFAccountWebService.jar,具体怎么生成就是我接下来要讲的内容,再讲这个之前先讲讲怎么通过Salesforce平台的权限。

通过Salesforce平台权限

在Salesforce中创建了自己需要用到的对象后,我们想要在别的应用中读写纪录到对象中,首先需要的是自己Salesforce平台的权限通过。登陆自己的Salesforce,下载WSDL文件。

  1. 下载Salesforce平台中WSDL文件
    依次点击Your Name --> Setup --> App Setup --> Develop --> API。或者直接在搜索框中搜索API。

    分别下点生成企业WSDL,生成合作伙伴WSDL,生成元数据WSDL。点击鼠标右键将文件另保存,可为.xml的形式也可以为.wsdl的文件形式
  2. 下载并构建WSC Jar,然后把对应的wsdl文件编译成对应jar
    下面是需要的Jar包下载地址。
  • Wsc.jar 下载地址:(https://mvnrepository.com/artifact/com.force.api/force-wsc) 选择最新版本的
  • ST4-4.0.8.jar (https://www.stringtemplate.org/download.html)
  • Antlr-runtime-3.5.2.jar (https://mvnrepository.com/artifact/org.antlr/antlr-runtime/3.5.2)
  • Tools.jar (安装jdk的目录下有,无需下载。直接复制)

    把刚才下载的jar包和3个wsdl文件放在同一个文件夹中(以下enterprise.jar,metadata.jar,partner.jar是通过下面cmd命令生成jar的)

    打开cmd,将路径定位到刚才的文件目录。
    然后执行以下命令生成对应的Jar包
  • 生成partner.jar
java -classpath antlr-runtime-3.5.2.jar:ST-4.3.jar:tools.jar:force-wsc-49.2.0.jar com.sforce.ws.tools.wsdlc wsdl.jsp.xml partner.jar
  • 生成enterprise.jar
java -classpath antlr-runtime-3.5.2.jar:ST-4.3.jar:tools.jar:force-wsc-49.2.0.jar com.sforce.ws.tools.wsdlc wsdl.xml enterprise.jar
  • 生成metadata.jar
java -classpath antlr-runtime-3.5.2.jar:ST-4.3.jar:tools.jar:force-wsc-49.2.0.jar com.sforce.ws.tools.wsdlc metadata.xml metadata.jar

java成熟saas框架 java saas_Salesforce_03


这个时候文件夹的文件如下:

java成熟saas框架 java saas_jar_04

  1. 创建程序并引用外部jar文件
    创建一个java project命名为TestWebService,然后将partner.jarmetadata.jarenterprise.jarforce-wsc-49.2.0.jar引入外部Jar包(右键项目,选择Build Path,然后选择Libraries,点击Add External JARS
  2. 测试程序
package wsc;

import com.sforce.soap.enterprise.Connector;
import com.sforce.soap.enterprise.DeleteResult;
import com.sforce.soap.enterprise.EnterpriseConnection;
import com.sforce.soap.enterprise.Error;
import com.sforce.soap.enterprise.QueryResult;
import com.sforce.soap.enterprise.SaveResult;
import com.sforce.soap.enterprise.sobject.Account;
import com.sforce.soap.enterprise.sobject.Contact;
import com.sforce.ws.ConnectionException;
import com.sforce.ws.ConnectorConfig;

public class Main {
  
static final String USERNAME = "YOUR-USERNAME";                   //Salesforce账号中的用户名
static final String PASSWORD = "YOUR-PASSWORD&SECURITY-TOKEN";    //密码,这个密码有点特殊,需要在密码后面加入安全标记
  static EnterpriseConnection connection;

  public static void main(String[] args) {

    ConnectorConfig config = new ConnectorConfig();
    config.setUsername(USERNAME);
    config.setPassword(PASSWORD);
        
    try {
      
      connection = Connector.newConnection(config);
      // 增删改查
      queryContacts();
      createAccounts();
      updateAccounts();
      deleteAccounts();
      
      
    } catch (ConnectionException e1) {
        e1.printStackTrace();
    }  

  }
  
  // queries and displays the 5 newest contacts
  private static void queryContacts() {
    
    System.out.println("Querying for the 5 newest Contacts...");
    
    try {
       
      // query for the 5 newest contacts      
      QueryResult queryResults = connection.query("SELECT Id, FirstName, LastName, Account.Name " +
              "FROM Contact WHERE AccountId != NULL ORDER BY CreatedDate DESC LIMIT 5");
      if (queryResults.getSize() > 0) {
        for (int i=0;i<queryResults.getRecords().length;i++) {
          // cast the SObject to a strongly-typed Contact
          Contact c = (Contact)queryResults.getRecords()[i];
          System.out.println("Id: " + c.getId() + " - Name: "+c.getFirstName()+" "+
              c.getLastName()+" - Account: "+c.getAccount().getName());
        }
      }
      
    } catch (Exception e) {
      e.printStackTrace();
    }    
    
  }
  
  // create 5 test Accounts
  private static void createAccounts() {
    
    System.out.println("Creating 5 new test Accounts...");
    Account[] records = new Account[5];
    
    try {
       
      // create 5 test accounts
      for (int i=0;i<5;i++) {
        Account a = new Account();
        a.setName("Test Account "+i);
        records[i] = a;
      }
      
      // create the records in Salesforce.com
      SaveResult[] saveResults = connection.create(records);
      
      // check the returned results for any errors
      for (int i=0; i< saveResults.length; i++) {
        if (saveResults[i].isSuccess()) {
          System.out.println(i+". Successfully created record - Id: " + saveResults[i].getId());
        } else {
          Error[] errors = saveResults[i].getErrors();
          for (int j=0; j< errors.length; j++) {
            System.out.println("ERROR creating record: " + errors[j].getMessage());
          }
        }    
      }
      
    } catch (Exception e) {
      e.printStackTrace();
    }    
    
  }
  
  // updates the 5 newly created Accounts
  private static void updateAccounts() {
    
    System.out.println("Update the 5 new test Accounts...");
    Account[] records = new Account[5];
    
    try {
       
      QueryResult queryResults = connection.query("SELECT Id, Name FROM Account ORDER BY " +
              "CreatedDate DESC LIMIT 5");
      if (queryResults.getSize() > 0) {
        for (int i=0;i<queryResults.getRecords().length;i++) {
          // cast the SObject to a strongly-typed Account
          Account a = (Account)queryResults.getRecords()[i];
          System.out.println("Updating Id: " + a.getId() + " - Name: "+a.getName());
          // modify the name of the Account
          a.setName(a.getName()+" -- UPDATED");
          records[i] = a;
        }
      }
      
      // update the records in Salesforce.com
      SaveResult[] saveResults = connection.update(records);
      
      // check the returned results for any errors
      for (int i=0; i< saveResults.length; i++) {
        if (saveResults[i].isSuccess()) {
          System.out.println(i+". Successfully updated record - Id: " + saveResults[i].getId());
        } else {
          Error[] errors = saveResults[i].getErrors();
          for (int j=0; j< errors.length; j++) {
            System.out.println("ERROR updating record: " + errors[j].getMessage());
          }
        }    
      }
      
    } catch (Exception e) {
      e.printStackTrace();
    }    
    
  }
  
  // delete the 5 newly created Account
  private static void deleteAccounts() {
    
    System.out.println("Deleting the 5 new test Accounts...");
    String[] ids = new String[5];
    
    try {
       
      QueryResult queryResults = connection.query("SELECT Id, Name FROM Account ORDER BY " +
              "CreatedDate DESC LIMIT 5");
      if (queryResults.getSize() > 0) {
        for (int i=0;i<queryResults.getRecords().length;i++) {
          // cast the SObject to a strongly-typed Account
          Account a = (Account)queryResults.getRecords()[i];
          // add the Account Id to the array to be deleted
          ids[i] = a.getId();
          System.out.println("Deleting Id: " + a.getId() + " - Name: "+a.getName());
        }
      }
      
      // delete the records in Salesforce.com by passing an array of Ids
      DeleteResult[] deleteResults = connection.delete(ids);
      
      // check the results for any errors
      for (int i=0; i< deleteResults.length; i++) {
        if (deleteResults[i].isSuccess()) {
          System.out.println(i+". Successfully deleted record - Id: " + deleteResults[i].getId());
        } else {
          Error[] errors = deleteResults[i].getErrors();
          for (int j=0; j< errors.length; j++) {
            System.out.println("ERROR deleting record: " + errors[j].getMessage());
          }
        }    
      }
      
    } catch (Exception e) {
      e.printStackTrace();
    }    
    
  }
 
}
SECURITY TOKEN

由于登录时的密码需要拼接Security Token,但不知道Security Token是什么,这个时候需要到Salesforce中重置Security Token,新的Security Token会发送到对应的邮箱。

重置Token的网址为:“https://[SalesforceDomainHere]/_ui/system/security/ResetApiTokenEdit?retURL=%2Fui%2Fsetup%2FSetup%3Fsetupid%3DPersonalInfo&setupid=ResetApiToken”

java成熟saas框架 java saas_java成熟saas框架_05


获取到对应的Token后直接在代码的密码后面拼接Token即可,如下图:

java成熟saas框架 java saas_java_06

省略SECURITY TOKEN

登录时密码部分需要添加对应的SECURITY-TOKEN

  1. SET UP的搜索框输入profiles,点击进入,在列表中找到[System Administrator]并点击进入
  2. 鼠标滑动到 [Login IP Ranges]上,点击New
  3. Start IP Address终输入0.0.0.0End IP Address中输入255.255.255.255,点击Save保存。
运行结果

java成熟saas框架 java saas_java_07


补充:

  1. 如果想在Java中调用Salesforce中编写的Apex Class,例如开篇我们创建SFAccountWebService.class,同样的我们也需要将其生成对应的JAR包,例如:
java -classpath antlr-runtime-3.5.2.jar:ST-4.3.jar:tools.jar:force-wsc-49.2.0.jar com.sforce.ws.tools.wsdlc SFAccountWebService.xml SFAccountWebService.jar

然后导入到eclipse的项目中利用即可。

  1. 例子中如果需要用到新的对象,比如我自己创建的案件明细对象,那么可以在对象的详细页面找到对象对应的api名称,以及对象中字段api名称,如下图

    找到对应的api名称后,如果需要创建一条Position纪录,那么可以这样new一个对象 OP_Item__c a = new OP_Item__c(); 然后通过Set的扩展方法来对对象字段的值进行赋值便可。