Salesforce Apex (基础3)操作记录

学习目标

完成本单元后,您将能够:

  • 使用DML插入,更新和删除记录。
  • 批量执行DML语句。
  • 使用upsert来插入或更新记录。
  • 捕获一个DML异常。
  • 使用数据库方法插入具有部分成功选项的新记录并处理结果。
  • 知道何时使用DML语句以及何时使用数据库方法。
  • 对相关记录执行DML操作

用DML操作记录

使用数据操作语言(简称DML)在Salesforce中创建和修改记录。 DML通过提供简单的语句来插入,更新,合并,删除和恢复记录,提供了一种直接管理记录的方法。
由于Apex是一种以数据为中心的语言,并保存在Force.com平台上,因此可直接访问Salesforce中的数据。与其他需要额外设置以连接数据源的编程语言不同,使用Apex DML,管理记录变得非常简单!通过调用DML语句,您可以快速对Salesforce记录执行操作。

此示例将Acme客户添加到Salesforce。首先创建一个客户sObject,然后将其作为参数传递给insert语句,该语句在Salesforce中保留该记录。

// 创建客户sObject
Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100);
// 通过使用DML插入客户
insert acct;

DML语句

以下DML语句可用。

  • insert
  • update
  • upsert
  • delete
  • undelete
  • merge

每个DML语句接受一个单独的sObject或一个sObject的列表(或数组)。在sObjects列表上操作是处理记录的更有效的方法。

除了一对,所有这些陈述都是熟悉的数据库操作。 upsert和merge语句是Salesforce特有的,可以非常方便。

upsert DML操作创建新记录,并在单个语句中更新sObject记录,使用指定的字段确定现有对象的存在,或者在没有指定字段的情况下使用ID字段。

合并语句将最多三个相同sObject类型的记录合并到其中一个记录中,删除其他记录,并将所有相关记录重新归类。

ID字段自动分配到新记录

插入记录时,系统为每个记录分配一个ID。除了在数据库中保存ID值之外,还可以在用作DML调用中的参数的sObject变量上自动填充ID值。

这个例子展示了如何获得对应于插入客户的sObject的ID。

// 创建客户sObject
Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100);
// 通过使用DML插入客户
insert acct;

// 获取插入的sObject参数的新ID
ID acctID = acct.Id;
// 在调试日志中显示此ID
System.debug('ID = ' + acctID);

// 调试日志结果(在您的情况下ID将不同)
// DEBUG|ID = 001D000000JmKkeIAF

超越基础

由于示例中的sObject变量包含DML调用后的ID,因此您可以重新使用此sObject变量来执行进一步的DML操作(如更新),因为系统可以通过匹配ID来将sObject变量映射到其对应的记录。

您可以从数据库检索记录以获取其字段,包括ID字段,但这不能用DML完成。您需要使用SOQL编写查询。您将在另一个单元学习SOQL。

批量 DML

您可以在单个sObject上执行DML操作,也可以在sObjects列表上批量执行DML操作。执行批量DML操作是推荐的方法,因为它有助于避免触及限额,例如每个Apex交易的DML限制为150条语句。这个限制是为了确保公平地访问Force.com多租户平台中的共享资源。在sObjects列表上执行DML操作会计算为列表中所有sObjects的一个DML语句,而不是每个sObject的一个语句。

此示例通过在一次调用中插入联系人列表来批量插入联系人。该示例然后批量更新这些联系人。

  1. 在开发者控制台中使用Anonymous Apex执行此代码段。
    // 创建联系人列表
    List<Contact> conList = new List<Contact> {
        new Contact(FirstName='Joe',LastName='Smith',Department='Finance'),
            new Contact(FirstName='Kathy',LastName='Smith',Department='Technology'),
            new Contact(FirstName='Caroline',LastName='Roth',Department='Finance'),
            new Contact(FirstName='Kim',LastName='Shain',Department='Education')};
                
    // 用一个DML调用批量插入所有联系人
    insert conList;
    
    // List来保存新的联系人进行更新
    List<Contact> listToUpdate = new List<Contact>();
    
    // 遍历列表并仅添加标题
    //  如果部门是财务部门
    for(Contact con : conList) {
        if (con.Department == 'Finance') {
            con.Title = 'Financial analyst';
            // Add updated contact sObject to the list.
            listToUpdate.add(con);
        }
    }
    
    // 将更新的联系人sObject添加到列表中。
    update listToUpdate;
    
  2. 检查最近在您的组织中创建的联系人。
    两位在财务部门的联系人应该有他们的头衔,财务分析师。

插入记录

如果您有一个包含新记录和现有记录混合的列表,则可以使用upsert语句来处理对列表中所有记录的插入和更新。 Upsert有助于避免重复记录的创建,并且可以节省时间,因为您不必先确定哪些记录存在。

upsert语句通过比较一个字段的值来将sObjects与现有记录进行匹配。如果调用此语句时未指定字段,则upsert语句将使用sObject的ID将sObject与Salesforce中的现有记录进行匹配。或者,您可以指定一个字段用于匹配。对于自定义对象,请指定标记为外部标识的自定义字段。对于标准对象,可以指定任何idLookup属性设置为true的字段。例如,联系人或用户的电子邮件字段设置了idLookup属性。要检查字段的属性,请参阅Salesforce和Force.com的对象参考。

Upsert语法

upsert sObject | sObject[]

upsert sObject | sObject[]​​ field

可选字段是字段标记。例如,要指定MyExternalID字段,该语句是:

upsert sObjectList Account.Fields.MyExternalId;

Upsert使用sObject记录的主键(ID),idLookup字段或外部ID字段来确定是否应该创建新记录或更新现有记录:

  • 如果密钥不匹配,则创建一个新的对象记录。
  • 如果密钥匹配一次,则更新现有对象记录。
  • 如果密钥匹配多次,则会生成错误,并且不会插入或更新对象记录。

这个例子显示了upsert如何更新一个现有的联系人记录,并在一个呼叫中插入一个新的联系人。这个upsert调用更新现有的Josh联系人并插入一个新的联系人Kathy。

注意

upsert调用使用该ID来匹配第一个联系人。 josh变量正被重新用于upsert调用。这个变量已经被填充了上一次插入调用的记录ID,所以在这个例子中不需要显式地设置ID。

  1. 在开发者控制台的“执行匿名”窗口中执行此代码段。
    //插入Josh联系人
    Contact josh = new Contact(FirstName='Josh',LastName='Kaplan',Department='Finance');       
    insert josh;
    
    // Josh's 的记录已被插入
    //   所以变量josh现在有一个ID
    //   将用于通过upsert匹配记录
    josh.Description = 'Josh\'s record has been updated by the upsert operation.';
    
    // 创建Kathy联系人,但不要将其保存在数据库中
    Contact kathy = new Contact(FirstName='Kathy',LastName='Brown',Department='Technology');
    
    // 列举以保持新联系人upsert
    List<Contact> contacts = new List<Contact> { josh, kathy };
    
    // 调用upsert
    upsert contacts;
    
    // 结果:Josh被更新,Kathy被创建。
  2. 检查组织中的所有联系人。
    您的组织只有一个Josh Kaplan记录,而不是两个,因为upsert操作找到了现有记录并进行了更新,而不是创建新的联系人记录。凯西·布朗的一个联系记录也将在那里。或者,您可以指定一个字段用于匹配记录。此示例使用Contact上的电子邮件字段,因为它具有idLookup属性集。该示例插入Jane Smith联系人,并创建第二个Contact sObject,使用相同的电子邮件填充它,然后使用电子邮件字段进行匹配以调用upsert以更新联系人。

注意

如果在这个例子中使用了插入而不是upsert,那么将会插入一个重复的Jane Smith联系人。

  1. 在开发者控制台的“执行匿名”窗口中执行此代码段。
    Contact jane = new Contact(FirstName='Jane',
                             LastName='Smith',
                             Email='jane.smith@example.com',
                             Description='Contact of the day');
    insert jane;
    
    // 1.使用idLookup字段的Upsert
    // 创建第二个sObject变量。
    // 这个变量没有任何ID设置。
    Contact jane2 = new Contact(FirstName='Jane',
                             LastName='Smith',  
                             Email='jane.smith@example.com',
                             Description='Prefers to be contacted by email.');
    // 通过使用idLookup字段进行匹配来提升联系人。
    upsert jane2 Contact.fields.Email;
    
    // 确认联系人已更新
    System.assertEquals('Prefers to be contacted by email.',
                       [SELECT Description FROM Contact WHERE Id=:jane.Id].Description);
    
  2. 检查组织中的所有联系人。

    您的组织将只有一个Jane Smith联系更新后的描述。

删除记录

您可以使用delete语句删除持久记录。删除的记录不会从Force.com永久删除,但是它们可以从恢复位置放置在回收站中15天。

此示例显示如何删除姓氏为Smith的所有联系人。如果您已经为批量DML运行了样本,那么您的组织应该与Smith的姓氏有两个联系。在开发人员控制台中使用匿名Apex执行此代码段,然后验证是否没有与姓氏Smith的联系人。

Contact[] contactsDel = [SELECT Id FROM Contact WHERE LastName='Smith']; 
delete contactsDel;

注意

这个片段包含一个查询来检索联系人(一个SOQL查询)。你会在另一个单元学到更多关于SOQL的知识。

DML语句异常

如果DML操作失败,则返回DmlException类型的异常。您可以在代码中捕获异常以处理错误情况。

这个例子产生了一个DmlException,因为它试图插入一个没有必需的Name字段的客户。 catch块中捕获到异常。

try {
    // 这会导致异常
    //   不提供必需的名称字段。
    Account acct = new Account();
    // 插入客户
    insert acct;
} catch (DmlException e) {
    System.debug('A DML exception has occurred: ' +
                e.getMessage());
}

数据库方法

Apex包含内置的Database类,它提供执行DML操作和镜像DML语句对应的方法。
这些数据库方法是静态的,并在类名称上调用。
  • Database.insert()
  • Database.update()
  • Database.upsert()
  • Database.delete()
  • Database.undelete()
  • Database.merge()

与DML语句不同,数据库方法有一个可选的allOrNone参数,允许您指定操作是否应该部分成功。当此参数设置为false时,如果在部分记录集上发生错误,则成功的记录将被提交,并且将为失败的记录返回错误。另外,部分成功选项也不会引发异常。

这是你如何调用allOrNone设置为false的插入方法。

Database.insert(recordList, false);
Database方法返回包含每条记录的成功或失败信息的结果对象。例如,insert和update操作每个都返回一个Database.SaveResult对象的数组。
Database.SaveResult[] results = Database.insert(recordList, false);

注意

Upsert返回Database.UpsertResult对象,并删除返回的Database.DeleteResult对象。

默认情况下,allOrNone参数为true,这意味着Database方法的行为与其DML语句相对应,如果遇到故障,则会引发异常。

以下两条语句相当于insert recordList;声明。

Database.insert(recordList);
和:
Database.insert(recordList, true);

超越基础

除了这些方法外,Database类还包含不作为DML语句提供的方法。例如,用于事务控制和回滚的方法,用于清空回收站以及与SOQL查询相关的方法。您将在另一个单元学习SOQL。

示例:以部分成功插入记录

我们来看看使用数据库方法的例子。此示例基于批量DML示例,但是用Database方法替换了DML语句。用部分成功选项调用Database.insert()方法。列表中的一个联系人没有任何有意使用的字段,并且会导致错误,因为如果没有所需的姓氏字段,则无法保存联系人。三个联系人被提交,没有任何字段的联系人会产生错误。本示例的最后一部分遍历返回的结果并将调试消息写入调试日志。

  1. 在开发者控制台的“执行匿名”窗口中执行此示例。
    // 创建联系人列表
    List<Contact> conList = new List<Contact> {
            new Contact(FirstName='Joe',LastName='Smith',Department='Finance'),
            new Contact(FirstName='Kathy',LastName='Smith',Department='Technology'),
            new Contact(FirstName='Caroline',LastName='Roth',Department='Finance'),
            new Contact()};
                
    // 用一个DML调用批量插入所有联系人
    Database.SaveResult[] srList = Database.insert(conList, false);
    
    // 遍历每个返回的结果
    for (Database.SaveResult sr : srList) {
        if (sr.isSuccess()) {
            // 操作成功,所以得到处理记录的ID
            System.debug('Successfully inserted contact. Contact ID: ' + sr.getId());
        } else {
            // 操作失败,所以得到所有的错误
            for(Database.Error err : sr.getErrors()) {
                System.debug('The following error has occurred.');
                System.debug(err.getStatusCode() + ': ' + err.getMessage());
                System.debug('Contact fields that affected this error: ' + err.getFields());
    	 }
        }
    }
    
  2. 验证调试消息(使用过滤器的DEBUG关键字)。
    应该报告一个故障,应该插入三个联系人。

你应该使用DML语句还是数据库方法?

  • 如果希望在批量DML处理期间发生的任何错误作为立即中断控制流的Apex异常(通过使用try。。catch块)引发,请使用DML语句。这种行为类似于大多数数据库过程语言中处理异常的方式。
  • 如果要允许批量DML操作的部分成功,请使用Database类方法 – 如果记录失败,则DML操作的其余部分仍可能成功。然后您的应用程序可以检查被拒绝的记录,并可能重试该操作。使用此表单时,您可以编写不会抛出DML异常错误的代码。相反,您的代码可以使用适当的结果数组来判断成功或失败。请注意,数据库方法还包括一个支持抛出异常的语法,类似于DML语句。

Salesforce Apex (基础2)sObjects

学习目标

完成本单元后,您将能够:

  • 描述sObjects和Salesforce记录之间的关系。
  • 创建并使用特定的sObject变量。
  • 将一个通用的sObject转换为一个特定的sObject。

使用sObjects

由于Apex与数据库紧密集成,因此您可以直接从Apex访问Salesforce记录及其字段。 Salesforce中的每个记录都本地表示为Apex中的sObject。例如,Acme客户记录对应于Apex中的Account sObject。您可以在用户界面中查看和修改的Acme记录的字段也可以在sObject上直接读取和修改。
下表列出了Acme客户示例记录的一些填充字段。 Account sObject是客户记录的抽象,并将客户字段信息作为对象保存在内存中。
表1.检索到的记录的AccountSObject
客户字段
Id 001D000000JlfXe
公司名称 Acme
电话 (415)555-1212
员工人数 100

每个Salesforce记录在插入Salesforce之前都被表示为一个sObject。同样,从Salesforce检索持久性记录时,它们存储在sObject变量中。

Salesforce中的标准和自定义对象记录将映射到Apex中的sObject类型。以下是Apex中用于标准对象的一些常用的sObject类型名称。

  • 客户
  • 联系
  • 潜在客户
  • 机会

如果您在组织中添加了自定义对象,请使用Apex中自定义对象的API名称。例如,名为Merchandise的自定义对象对应于Apex中的Merchandise__c sObject。

创建sObject变量

要创建一个sObject,你需要声明一个变量并将其分配给一个sObject实例。变量的数据类型是sObject类型。

以下示例创建一个类型为Account的sObject变量,并将其分配给名称为Acme的新客户。

Account acct = new Account(Name='Acme');

sObject和字段名称

sObjects的名称对应于相应的标准或自定义对象的API名称。同样,sObject字段的名称对应于相应字段的API名称。

对象和字段的API名称可能与标签不同。例如,“雇员”字段具有“雇员”标签,并在“客户记录”页面上显示为“雇员”,但其API名称为“NumberOfEmployees”。要在Apex中访问此字段,您需要使用该字段的API名称:NumberOfEmployees。

以下是用于自定义对象和自定义字段的API名称的一些规则的亮点。

对于自定义对象和自定义字段,API名称始终以__c后缀结尾。对于自定义关系字段,API名称以__r后缀结尾。例如:

  • 具有Merchandise 标签的自定义对象具有Merchandise__c的API名称。
  • 描述标签的自定义字段的API名称为Description__c。
  • 具有Items标签的自定义关系字段具有Items__r的API名称。

另外,标签中的空格在API名称中用下划线代替。例如,Employee Seniority的自定义字段名称具有Employee_Seniority__c的API名称。

查找对象和字段名称

要查找在Apex中使用的标准对象及其字段的名称,请参阅Salesforce和Force.com的对象参考。

对于自定义对象,请在您的组织中查找对象和字段API名称。从“设置”中,在“快速查找”框中输入对象,然后选择“对象”,然后单击对象的名称。

创建sObjects和添加字段

在插入Salesforce记录之前,必须首先在内存中创建它作为sObject。与其他任何对象一样,sObject使用新的运算符创建:

Account acct = new Account();

API对象名称成为Apex中sObject变量的数据类型。在这个例子中,Account是acct变量的数据类型。

由acct变量引用的客户是空的,因为我们还没有填充它的任何字段。有两种方法可以添加字段:通过构造函数或使用点符号。

添加字段的最快方法是在构造函数中将它们指定为名称 – 值对。例如,这个语句创建一个新的客户sObject,并用字符串值填充它的Name字段。

Account acct = new Account(Name='Acme');
名称字段是客户唯一必填字段,这意味着必须在插入新记录之前填充该字段。但是,您也可以填充其他字段以及新记录。这个例子还增加了一个电话号码和雇员的数量。
Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100);
或者,您可以使用点符号将字段添加到sObject。以下示例与前面的示例相同,但需要多行代码。
Account acct = new Account();
acct.Name = 'Acme';
acct.Phone = '(415)555-1212';
acct.NumberOfEmployees = 100;

使用通用的sObject数据类型

通常,在使用sObjects时,使用特定的sObject数据类型(例如标准对象的Account或Book__c)作为名为Book的自定义对象。但是,当您不知道您的方法正在处理的sObject类型时,可以使用通用的sObject数据类型。
使用通用sObject数据类型声明的变量可以引用任何Salesforce记录,无论它是标准还是自定义对象记录。
A generic sObject variable can point to any Salesforce record

此示例显示如何将通用的sObject变量分配给任何Salesforce对象:客户和名为Book__c的自定义对象。

sObject sobj1 = new Account(Name='Trailhead');
sObject sobj2 = new Book__c(Name='Workbook 1');
相比之下,使用特定的sObject数据类型声明的变量只能引用相同类型的Salesforce记录。
A specific sObject variable can point to the Salesforce record of the same type only

将泛型对象转换为特定的对象类型

当你处理通用的sObjects时,你有时需要将你的sObject变量转换为特定的sObject类型。这样做的好处之一就是能够使用点符号访问字段,这在通用的sObject上是不可用的。由于sObject是所有特定sObject类型的父类型,因此可以将通用sObject转换为特定的sObject。这个例子展示了如何将一个通用的sObject转换为Account。

// 将一个通用的sObject转换为一个Account
Account acct = (Account)myGenericSObject;
// 现在,您可以使用点符号来访问客户上的字段Account
String name = acct.Name;
String phone = acct.Phone;

告诉我更多…

与特定的sObjects类型不同,通用sObjects只能通过newSObject()方法创建。而且,只能通过put()和get()方法访问通用sObject的字段。

在这个单元中,你已经学习了什么sObjects以及如何使用它们。但是,创建一个sObject并不会将其作为记录保存在数据库中。要将sObject保存为记录,并用它来做其他事情,请使用数据操作语言(DML)。要检索记录,请使用Salesforce对象查询语言(SOQL)。查看以后的单元,了解DML和SOQL。

Salesforce Apex (基础1)入门

学习目标

完成本单元后,您将能够:

  • 描述Apex编程语言的主要特点。
  • 保存Apex类并使用Anonymous.Apex调用方法。
  • 使用开发者控制台检查调试日志。

Apex入门

Apex是一种使用类似Java的语法的编程语言,像数据库存储过程一样行事。 Apex使开发人员能够将业务逻辑添加到系统事件中,如按钮点击,相关记录更新和Visualforce页面。

作为一种语言,Apex是:

  • Hosted-Apex在服务器(Force.com平台)上保存,编译并执行。
  • 面向对象-Apex支持类,接口和继承。
  • 强类型-Apex在编译时验证对对象的引用。
  • 多租户感知 – 因为Apex运行在多租户平台上,所以它通过强制实施限制防止代码独占共享资源,从而防止代码走失。
  • 与数据库集成 – 访问和操作记录非常简单。 Apex提供对记录及其字段的直接访问,并提供语句和查询语言来操作这些记录。
  • 关注数据–Apex提供对数据库的事务访问,允许您回滚操作。
  • 易于使用-Apex基于熟悉的Java成语。
  • 易于测试 – Apex为单元测试创​​建,执行和代码覆盖提供了内置的支持。
  • Salesforce确保所有定制的Apex代码在任何平台升级之前执行所有单元测试,并按预期工作。
  • Versioned-Custom Apex代码可以针对不同版本的API进行保存。
Apex is a cloud-based programming language

Apex 语言亮点

像其他面向对象的编程语言一样,这些是Apex支持的一些语言结构:

  • 类,接口,属性和集合(包括数组)。
  • 对象和数组表示法。
  • 表达式,变量和常量。
  • 条件语句(if-then-else)和控制流语句(for循环和while循环)。

与其他面向对象的编程语言不同,Apex支持:

  • 作为Apex的云开发是在云中存储,编译和执行的。
  • 触发器,类似于数据库系统中的触发器。
  • 数据库语句,允许您直接进行数据库调用和查询语言来查询和搜索数据。
  • 事务和回滚。
  • 全局访问修饰符,它比public修饰符更宽松,并允许跨命名空间和应用程序访问。
  • 自定义代码的版本。

另外,Apex是一个不区分大小写的语言。

开发工具

您可以使用Salesforce用户界面直接在浏览器中编写Apex并访问调试信息。打开您的名字下的开发者控制台或快速访问菜单(设置齿轮图标)。

您也可以使用Eclipse的Force.com IDE插件在客户端上编写Apex。请参阅Salesforce Developer网站上的Force.com IDE。

数据类型概述

Apex支持各种数据类型,包括特定于Salesforce的数据类型(sObject数据类型)。
Apex支持以下数据类型。

  • 诸如Integer,Double,Long,Date,Datetime,String,ID,Boolean等原语。
  • 一个sObject,或者作为一个通用的sObject或者一个特定的sObject,比如一个Account,Contact或者MyCustomObject__c(你将在后面的单元中学到更多关于sObjects的知识)。
  • 收藏品包括:
    • 基元,sObjects,用户定义的对象,从Apex类创建的对象或集合的列表(或数组)
    • 一组原语
    • 从基元到基元,sObject或集合的映射
  • 一个键入的值列表,也被称为枚举
  • 用户定义的Apex类
  • 系统提供的Apex类

Apex收藏:列表

列表包含对象的有序集合。 Apex中的列表与数组同义,两者可以互换使用。

以下两个声明是等价的。 colors变量是使用List语法声明的。

List<String> colors = new List<String>();
另外,颜色变量可以声明为一个数组,但分配给一个列表而不是一个数组。
String[] colors = new List<String>();

通常,创建列表而不是数组会更容易,因为列表不需要提前确定需要分配多少个元素。

您可以在创建列表时将元素添加到列表中,或者通过调用add()方法创建列表后添加元素。这第一个例子显示了向元素添加元素的两种方法。

// 创建一个列表并向其中添加元素
List<String> colors = new List<String> { 'red', 'green', 'blue' };

// 创建元素后,将元素添加到列表中
List<String> moreColors = new List<String>();
moreColors.add('orange');
moreColors.add('purple');
列表元素可以通过指定方括号之间的索引来读取,就像数组元素一样。另外,您可以使用get()方法读取列表元素。这个例子是基于前面例子中创建的列表,并展示了如何使用任一方法读取列表元素。该示例还显示了如何迭代数组元素。
// 从列表中获取元素
String color1 = moreColors.get(0);
String color2 = moreColors[0];
System.assertEquals(color1, color2);

// 遍历列表来读取元素
for(Integer i=0;i<colors.size();i++) {
    // Write value to the debug log
    System.debug(colors[i]);
}

超越基础

Apex支持另外两种集合类型:Set和Map。您可以在“Apex开发人员指南”的“集合”部分了解更多。

Apex 类

Apex类的好处之一是代码重用。类方法可以被触发器和其他类调用。以下教程将引导您保存组织中的示例类,使用此类发送电子邮件以及检查调试日志。

保存一个Apex类

将EmailManager类保存在您的组织中:

  1. 打开您的名字下的开发者控制台或快速访问菜单(设置齿轮图标Setup gear icon)。
  2. 在开发者控制台中,点击 File | New | Apex Class ,然后输入EmailManager作为类名称,然后单击OK。
  3. 用EmailManager类的例子替换默认的类体。

    EmailManager类具有公共方法(sendMail()),用于发送电子邮件并使用Apex类库的内置消息处理方法。另外,这个类有一个私有的帮助方法(inspectResults()),它不能被外部调用,因为它是私有的,但只在类中使用。这个帮助方法检查电子邮件发送调用的结果,并由sendMail()调用。

    public class EmailManager {
    
        // 公共方法
        public void sendMail(String address, String subject, String body) {
            // 创建一个电子邮件对象
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            String[] toAddresses = new String[] {address};
            mail.setToAddresses(toAddresses);
            mail.setSubject(subject);
            mail.setPlainTextBody(body);
            // 将此电子邮件传递给内置的sendEmail方法
            // 消息类的
            Messaging.SendEmailResult[] results = Messaging.sendEmail(
                                     new Messaging.SingleEmailMessage[] { mail });
            
            // 调用一个帮助器方法来检查返回的结果
            inspectResults(results);
        }
        
        // 辅助方法
        private static Boolean inspectResults(Messaging.SendEmailResult[] results) {
            Boolean sendResult = true;
            
            // sendEmail返回一个结果对象数组。
            // 遍历列表来检查结果。
            // 在这个类中,方法只发送一封邮件,
            // 所以我们应该只有一个结果。
            for (Messaging.SendEmailResult res : results) {
                if (res.isSuccess()) {
                    System.debug('Email sent successfully');
                }
                else {
                    sendResult = false;
                    System.debug('发生以下错误:' + res.getErrors());                 
                }
            }
            
            return sendResult;
        }
    
    }
  4. 点击Ctrl + S保存你的课程。

    超越基础

    刚刚保存的类使用面向对象编程(OOP)。该类封装了与管理电子邮件有关的方法。为了成为OOP的一个完美的例子,类还将包含成员变量(属性)和访问器方法来访问这些属性,但为了简单起见,我们的类没有这些。

    Salesforce在您保存时编译您的类。

调用方法发送电子邮件

我们来调用公共方法。我们将使用匿名的Apex执行来执行此操作。匿名Apex允许您即时运行代码行,并且是调用Apex的一种便捷方式,尤其是测试功能。与任何其他Apex执行一样,也会生成调试日志结果。

注意

还有其他方法可以通过触发器来调用Apex。您将在另一个模块中了解有关触发器的更多信息。

  1. 在开发者控制台中,点击 Debug | Open Execute Anonymous Window.
  2. 在打开的窗口中,输入以下内容。用您的电子邮件地址替换“您的电子邮件地址”。
    EmailManager em = new EmailManager();
    em.sendMail('Your email address', 'Trailhead Tutorial', '123 body');
    
  3. 点击 Execute.

    现在这个方法已经执行了,你应该在收件箱里收到一封电子邮件。查看你的电子邮件!

检查调试日志

调试日志对于调试代码很有用。当Apex方法执行时,调用会记录在调试日志中。而且,您可以将自己的调试消息写入日志,这有助于在出现错误时调试代码。由sendMail()调用的inspectResults()辅助方法使用System.debug()方法将消息写入日志,以指示电子邮件发送操作是成功还是有错误。您可以在执行该方法时生成的调试日志中查找这些消息。

  1. 在开发者控制台中,点击日志标签,然后双击列表中最近的日志。
  2. 选择 Debug Only 来过滤日志,以便仅显示System.debug()语句的日志行。
    Filter the debug log in the Developer Console to view debug messages

    注意

    另外,您可以通过在“筛选”字段中搜索任何关键字来筛选调试日志,或者通过选择任何其他选项来筛选调试日志。有关更多信息,请参阅日志检查器帮助。

    在过滤的日志视图中,您会看到以下消息,假设电子邮件发送没有错误。

    DEBUG|Email sent successfully

调用静态方法

因为我们类中的sendMail()方法不能访问类成员变量,所以它不需要是一个实例方法。让我们通过添加静态关键字到它的声明来将其更改为静态方法。静态方法比实例方法更容易调用,因为它们不需要在类的实例上调用,而是直接在类名上调用。

  1. 在开发人员控制台中,找到EmailManager类的打开选项卡,并将sendMail()方法定义的第一行修改为以下内容(唯一的变化是添加的static关键字)。
    public static void sendMail(String address, String subject, String body) {
  2. 按Ctrl + S保存该类。
  3. 修改“执行匿名”窗口中的语句以调用类名称上的静态方法。
    EmailManager.sendMail('Your email address', 'Trailhead Tutorial', '123 body');
    
  4. 点击 Execute.

    现在这个方法已经执行了,你可以像在前面的步骤一样检查你的电子邮件,以及可选的调试日志。

Salesforce Visualforce (基础9)自定义控制器

学习目标

完成本单元后,您将能够:

  • 解释一下自定义控制器是什么,并描述其关键属性。
  • 创建一个自定义控制器类。
  • 在Visualforce页面上使用自定义控制器。

自定义控制器介绍

自定义控制器包含可由Visualforce页面使用的自定义逻辑和数据操作。例如,自定义控制器可以检索要显示的项目列表,向外部Web服务发出调用,验证和插入数据等等,并且所有这些操作都将可用于Visualforce页面,该页面将其用作控制器。
在其他地方介绍了Visualforce如何支持用于构建Web应用程序的模型 – 视图 – 控制器(MVC)设计模式。控制器通常检索要在Visualforce页面中显示的数据,并包含响应页面操作而执行的代码(如正在单击的按钮)。当您使用标准控制器时,平台为您提供了大量的标准功能。

但是一个尺寸并不适合所有的,并不是所有的网络应用程序都是“标准的”。当你想覆盖现有的功能,通过应用程序自定义导航,使用标注或Web服务,或者如果你需要更好地控制信息的访问方式对于您的页面,Visualforce可让您占据统治地位。您可以使用Apex编写自定义控制器,并从头到尾完全控制您的应用逻辑。

创建一个使用自定义控制器的Visualforce页面

通过在<apex:page>控制器属性中引用控制器类的名称,将自定义控制器添加到Visualforce页面。
当您的页面使用自定义控制器时,不能使用标准控制器。页面使用不同的属性来设置自定义控制器。
  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入ContactsListController作为页面名称。
  2. 在编辑器中,用以下替换标记。
    <apex:page controller="ContactsListController">
        <apex:form>
            <apex:pageBlock title="Contacts List" id="contacts_list">
                
                <!-- Contacts List goes here -->
    
            </apex:pageBlock>
        </apex:form>
    </apex:page>
    当你试图保存这个页面时,你会得到一个错误,因为ContactsListController还不存在。不用担心,接下来我们会解决这个问题。

创建一个自定义控制器Apex类

自定义控制器只是一个Apex类,您可以使用Developer Console编写自己的类。
有许多系统和实用程序类可以帮助您编写自定义控制器逻辑,但将类用作自定义控制器的唯一要求是它存在。
  1. 打开开发者控制台,然后点击 File | New | Apex Class 创建一个新的Apex类。输入ContactsListController作为类名。
  2. 在编辑器中,用以下代码替换任何代码。
    public class ContactsListController {
    
        // Controller code goes here
    
    }
    与Visualforce页面一样,当您更改时,您需要保存对Apex的更改。
    这并不多,而且还没有做任何事情,但它确实使错误消失在Visualforce页面上。所以…
  3. 切换回Visualforce页面并再次保存。
    错误信息应该消失,页面成功保存。
  4. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    应该打开一个新窗口,显示标准的Salesforce页面标题和侧边栏元素,但没有内容。

乍一看,你创建的这两个新项目看起来并不是很有趣。但是即使它们是90%的占位符代码,Visualforce页面和Apex控制器这两个项目也是相互关联的。只要你添加更多的代码到控制器,你的页面就可以使用它。

超越基础

您可能已经注意到,这个自定义控制器类不会从另一个类继承,也不会实现一个有希望符合Visualforce控制器要求的接口。即使是复杂的控制器也不会做这些事情,因为没有任何这样的类继承或接口实现。这使您可以自由地创建自己的类和接口,随着您对Apex的经验的增加。

添加一个方法来检索记录

创建一个运行SOQL查询的getter方法,该查询返回要在页面上显示的记录。
大多数控制器的主要目的是检索显示数据或处理数据更新。在这个简单的控制器中,您只需运行一个基本的SOQL查询来查找联系人记录,然后使这些记录可用于Visualforce页面。
  1. 在ContactsListController类中,用下面的代码替换// Controller代码在这里注释行。
    private String sortOrder = 'LastName';
        
    public List<Contact> getContacts() {
        
        List<Contact> results = Database.query(
            'SELECT Id, FirstName, LastName, Title, Email ' +
            'FROM Contact ' +
            'ORDER BY ' + sortOrder + ' ASC ' +
            'LIMIT 10'
        );
        return results;
    }
    此代码添加一个私有成员变量,一个名为sortOrder的字符串和一个公共方法getContacts()。 sortOrder很容易理解,它只是通过排序联系人的字段的名称。
    getContacts()也是相当简单的,但是如果你以前没有见过Apex,可能起初很难解析。该方法的作用是执行SOQL查询以获取联系人记录列表,然后将该联系人列表返回给方法调用者。来电者是谁?当然是Visualforce页面!
  2. 在ContactsListWithController页面中,将<! – 联系人列表转到这里 – >注释行替换为以下标记。
    <!-- Contacts List -->
    <apex:pageBlockTable value="{! contacts }" var="ct">
    
        <apex:column value="{! ct.FirstName }"/>
        <apex:column value="{! ct.LastName }"/>
        <apex:column value="{! ct.Title }"/>
        <apex:column value="{! ct.Email }"/>
        
    </apex:pageBlockTable>
    当您保存此页面时,您应该看到一张熟悉的联系信息表格。
    A contacts list backed by a custom controller

ContactsListWithController页面的标记应该看起来相当熟悉。除了<apex:page>标签的控制器属性之外,它与用标准控制器创建页面的代码大致相同。

不同的是当{!联系人}表达式进行评估。在此页面上,Visualforce将该表达式转换为对控制器的getContacts()方法的调用。该方法返回联系人记录列表,这正是<apex:pageBlockTable>所期望的。

getContacts()方法被称为getter方法,它是一个通用模式,其中{!您的Visualforce标记中的someExpression}将自动连接到控制器中名为getSomeExpression()的方法。这是让页面访问需要显示的数据的最简单的方法。

添加一个新的操作方法

在自定义控制器中创建操作方法以响应用户在页面上的输入。
显示数据很棒,但是对用户操作的回应对于任何网络应用程序都是至关重要的使用自定义控制器,您可以通过编写操作方法来响应用户活动,从而创建尽可能多的自定义操作,以支持页面。
  1. 在ContactsListController类中,getContacts()方法的下面添加以下两个方法。
    public void sortByLastName() {
        this.sortOrder = 'LastName';
    }
        
    public void sortByFirstName() {
        this.sortOrder = 'FirstName';
    }
    这两个方法改变了sortOrder私有变量的值。在检索联系人的SOQL查询中使用sortOrder,并且更改sortOrder将更改结果的顺序。
  2. 在ContactsListWithController页面中,使用以下标记替换ct.FirstName和ct.LastName的两个<apex:column>标记。
    <apex:column value="{! ct.FirstName }">
        <apex:facet name="header">
            <apex:commandLink action="{! sortByFirstName }" 
                reRender="contacts_list">First Name
            </apex:commandLink>
        </apex:facet>
    </apex:column>
    
    <apex:column value="{! ct.LastName }">
        <apex:facet name="header">
            <apex:commandLink action="{! sortByLastName }" 
                reRender="contacts_list">Last Name
            </apex:commandLink>
        </apex:facet>
    </apex:column>

    尽管可视外观保持不变,但如果现在单击“名字和姓氏”列标题,它们将更改联系人列表的排序顺序。太好了!
    新的标记将两个嵌套组件添加到每个<apex:column>组件。 <apex:column>本身有一个纯文本标题,但是我们希望使标题可点击。 <apex:facet>让我们将列标题的内容设置为我们想要的任何内容。而我们想要的是一个调用正确的操作方法的链接。该链接是使用<apex:commandLink>组件创建的,action属性设置为引用控制器中action方法的表达式。 (请注意,与getter方法相比,action方法的名称与引用它们的表达式相同。)

    点击链接时,会触发控制器中的操作方法。该操作方法更改排序顺序专用变量,然后该表被重新渲染。当表格被重新渲染时,{!联系人}被重新评估,重新查询以任何排序顺序刚刚设置。最终的结果是按照用户点击所请求的顺序来使用表格。

超越基础

名字和姓氏列的标题文本在这个标记中被硬编码。但是,如果你的用户不全都使用英文呢?标准Salesforce用户界面已翻译所有标准对象的字段名称版本,并且可以为自定义对象提供自己的翻译。你将如何访问这些?试试这个标记,而不是纯文本:<apex:outputText value =“{!$ ObjectType.Contact.Fields.FirstName.Label}”/>。即使您的组织使用相同的语言,这也是引用字段标签的正确方法,因为如果字段名称被更改,它将自动更新。

告诉我更多…

自定义控制器和Apex语言让您可以在Visualforce页面中完成任何您能想到的任何事情。
Getter方法将数据从您的控制器中拖出到您的页面上。有相应的setter方法可以让你从页面提交值到你的控制器。就像getter方法一样,你在setter前面加上“set”,除此之外,它们只是一个方法。

getter和setter的替代方法是使用Apex属性。属性是一种变量与getter和setter方法的组合,它们的语法可以更清楚地将它们组合在一起。引用自定义对象的简单属性可能会这样声明。

public MyObject__c myVariable { get; set; }

属性可以是公共的或私有的,可以是只读的,甚至可以只写,通过省略get或set。你可以为get或set方法创建实现,当你想要执行额外的逻辑,除了简单地保存和检索一个值。

属性是Apex的一般功能,不是Visualfor特有的。 Apex是一种完整的编程语言,除了成为构建复杂的Visualforce页面的天然合作伙伴外,它还被用于许多其他的Force.com开发环境。请参阅此处其他位置的Apex主题以及本页末尾的资源,了解如何学习充分利用Apex。

Visualforce请求和响应的生命周期最初可能看起来很复杂。尤其重要的是要明白,没有特定的getter或setter(或属性,如果你使用它们)的顺序被调用,所以你不能在它们之间引入顺序执行的依赖关系。 Visualforce开发人员指南的相关章节中提供了更多详细信息,特别是“自定义控制器和控制器扩展”一章。

Salesforce Visualforce (基础8)静态资源

学习目标

完成本单元后,您将能够:

  • 解释什么样的静态资源以及为什么要使用它们。
  • 解释单个和压缩静态资源之间的差异。
  • 创建并上传一个静态资源。
  • 将静态资源添加到Visualforce页面。

静态资源简介

静态资源允许您上传可在Visualforce页面中引用的内容。资源可以是档案(如.zip和.jar文件),图像,样式表,JavaScript和其他文件。
静态资源由Force.com管理和分发,Force.com充当文件的内容分发网络(CDN)。缓存和分发是自动处理的。

静态资源使用$ Resource全局变量进行引用,该变量可以由Visualforce直接使用,也可以用作诸如URLFOR()之类的函数的参数。

创建并上传一个简单的静态资源

为独立的静态资产创建一个简单的,独立的静态资源。
当您的静态资产与其他资产无关时(即不是一组类似资产(如一组图标)的一部分),创建独立静态资源是最容易的。

  1. 下载jQuery JavaScript库的当前版本。在写这个是jQuery 3.1.0。
    如果链接不起作用,或者您想确保您正在下载最新版本,请访问http://jquery.com/download/并下载最新版本。

    注意

    右键单击直接链接下载文件,而不是在浏览器窗口中打开它。

  2. 在安装程序中,在快速查找框中输入静态资源,然后选择静态资源,然后单击新建。
  3. 输入名称的jQuery。
  4. 点击选择文件,然后选择您以前下载的jQuery JavaScript文件。
    Creating a simple static resource
  5. 如果看到缓存控制菜单,请选择公共。
    此项目在所有组织中都不可见。
  6. 点击 Save.

你现在有一个jQuery的静态资源版本,你可以在你的Visualforce页面中使用,通过在表达式中引用它,比如{! $ Resource.jQuery}。真正好的是,您可以编辑静态资源并将其更新到jQuery 3.1.2,而无需更改任何Visualforce页面。静态资源引用处理细节。

将一个静态资源添加到Visualforce页面

使用$ Resource全局变量和点符号来引用一个独立的静态资源。
  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入HelloJQuery作为页面名称。
  2. 在编辑器中,用以下替换标记。
    <apex:page>
        
        <!-- Add the static resource to page's <head> -->
        <apex:includeScript value="{! $Resource.jQuery }"/>
        
        <!-- A short bit of jQuery to test it's there -->
        <script type="text/javascript">
            jQuery.noConflict();
            jQuery(document).ready(function() {
                jQuery("#message").html("Hello from jQuery!");
            });
        </script>
        
        <!-- Where the jQuery message will appear -->
        <h1 id="message"></h1>
        
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    应打开一个新窗口,显示标准的Salesforce页面标题和侧边栏元素,以及jQuery的简短消息。
    除了说明如何在您的Visualforce页面上包含JavaScript资源之外,此页面没有太多工作。关键是使用$ Resource全局变量。使用点符号将它与<apex:includeScript>(用于JavaScript文件),<apex:stylesheet>(用于CSS样式表)或<apex:image>(用于图形文件)标签中的资源名称相结合它到你的页面。

创建和上传压缩的静态资源

创建压缩的静态资源,将通常一起更新的相关文件分组在一起。
当您的静态资产是一组相关项目(例如,一组应用程序图标或复杂的JavaScript库)时,最好创建一个压缩的静态资源。创建一个包含所有要组合在一起的元素的压缩文件,并仅将一个压缩文件上传到Force.com。

  1. 以ZIP格式下载当前版本的jQuery Mobile JavaScript库。在写这个是jQuery Mobile 1.4.5
    如果链接不起作用,或者您想确保您正在下载最新版本,请访问http://jquerymobile.com/download/并下载最新版本的ZIP文件。
  2. 在安装程序中,在快速查找框中输入静态资源,然后选择静态资源,然后单击新建。
  3. 输入名称的jQueryMobile。
  4. 点击选择文件,然后选择您以前下载的jQuery Mobile ZIP文件。
    Creating a zipped static resource
  5. 如果看到缓存控制菜单,请选择公共。
    此项目在所有组织中都不可见。
  6. 点击 Save.

    注意

    如果jQuery Mobile ZIP文件大于5 MB,则编辑压缩文件以除去/ demo /目录及其内容,并上传较小的zip压缩文件。

现在,您可以在Visualforce页面中使用jQuery Mobile的静态资源版本。您将学习如何在压缩的静态资源中引用单个文件。

将压缩的静态资源添加到Visualforce页面

使用$ Resource全局变量和URLFOR()函数来引用压缩静态资源中的项目。
URLFOR()函数可以将对压缩的静态资源的引用以及其中的项目的相对路径组合起来,以创建可用于引用静态资产的Visualforce组件的URL。例如,URLFOR($ Resource.jQueryMobile,’images / icons-png / cloud-black.png’)将URL返回到压缩静态资源中的特定图形资源,可以由<apex:image>组件使用。您可以为<apex:includeScript>和<apex:stylesheet>组件构建JavaScript和样式表文件的类似URL。
  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。
  2. 在编辑器中,用以下替换标记。
    <apex:page showHeader="false" sidebar="false" standardStylesheets="false">
        
        <!-- Add static resources to page's <head> -->
        <apex:stylesheet value="{!
              URLFOR($Resource.jQueryMobile,'jquery.mobile-1.4.5/jquery.mobile-1.4.5.css')}"/>
        <apex:includeScript value="{! $Resource.jQuery }"/>
        <apex:includeScript value="{!
             URLFOR($Resource.jQueryMobile,'jquery.mobile-1.4.5/jquery.mobile-1.4.5.js')}"/>
    
        <div style="margin-left: auto; margin-right: auto; width: 50%">
            <!-- Display images directly referenced in a static resource -->
            <h3>Images</h3>
            <p>A hidden message:
                <apex:image alt="eye" title="eye"
                     url="{!URLFOR($Resource.jQueryMobile, 'jquery.mobile-1.4.5/images/icons-png/eye-black.png')}"/>
                <apex:image alt="heart" title="heart"
                     url="{!URLFOR($Resource.jQueryMobile, 'jquery.mobile-1.4.5/images/icons-png/heart-black.png')}"/>
                <apex:image alt="cloud" title="cloud"
                     url="{!URLFOR($Resource.jQueryMobile, 'jquery.mobile-1.4.5/images/icons-png/cloud-black.png')}"/>
            </p>
    
        <!-- Display images referenced by CSS styles,
             all from a static resource. -->
        <h3>Background Images on Buttons</h3>
        <button class="ui-btn ui-shadow ui-corner-all
             ui-btn-icon-left ui-icon-action">action</button>
        <button class="ui-btn ui-shadow ui-corner-all
             ui-btn-icon-left ui-icon-star">star</button>
        </div>
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    打开一个新窗口,并显示来自jQuery Mobile静态资源的一些图像。

    jQuery buttons via static resources

为简单起见,此页面仅显示如何在Visualforce页面上引用压缩的静态资源。例如,如果您想了解更多关于如何结合Visualforce和JavaScript库(如jQuery Mobile)的更多资源,请参阅附加资源。

告诉我更多…

静态资源通常是将设计和脚本资产包含在Force.com应用程序中的最佳方式,并且可以通过多种方式将这些资源与Visualforce页面结合使用。
如果您喜欢为jQuery和jQuery Mobile组合一些静态资源,您将会喜欢我们预先打包的静态资源集合。 Salesforce Mobile Packs允许您使用行业标准网络技术(如HTML5,CSS3和JavaScript)以及流行的框架(如jQuery Mobile,AngularJS和Backbone.js)构建与Salesforce Platform集成的Web和混合应用程序。

Salesforce Visualforce (基础7)标准列表控制器

学习目标

完成本单元后,您将能够:

  • 解释Visualforce标准列表控制器是什么以及它与标准(记录)控制器有什么不同。
  • 列出标准列表控制器提供的与标准控制器不同的三个操作。
  • 在Visualforce页面上使用标准列表控制器显示记录列表。
  • 定义分页,并能够将其添加到Visualforce页面。

标准列表控制器简介

标准列表控制器允许您创建可以显示或执行一组记录的Visualforce页面。
显示记录列表是几乎所有Web应用程序的基本行为。 Visualforce使得显示相同类型的记录列表非常容易,只需使用标记,不需要后端代码。秘密,像往常一样,是标准的控制器,在这种情况下,标准的列表控制器。

标准列表控制器提供了许多强大的自动行为,例如查询特定对象的记录以及使集合变量中的记录可用,以及通过结果过滤和分页。将标准列表控制器添加到页面与添加标准(记录)控制器非常相似,但意图同时处理多条记录,而不是一次记录一条记录。

显示记录列表

使用标准列表控制器和迭代组件(如<apex:pageBlockTable>)来显示记录列表。
标准(记录)控制器可以轻松地将单个记录加载到您可以在Visualforce页面上使用的变量中。标准列表控制器是相似的,除了单个记录之外,它将记录的列表或集合加载到变量中。

因为你正在处理一个集合,而不是一个单独的记录,你需要使用一个迭代组件来显示它们。一个迭代组件与一组相似的项目一起工作,而不是一个单一的值。一个迭代组件循环遍历其集合,并且对于每个记录,基于作为组件标记的一部分提供的模板生成一些输出。这听起来很复杂,但是当你阅读标记时你会很快理解它。

使用标准列表控制器的标记与使用标准的一次一个记录控制器的标记几乎相同。为了显而易见,以下示例中以粗体突出显示了主要区别。

  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入ContactList作为页面名称。
  2. 在编辑器中,用以下替换标记。
    <apex:page standardController="Contact" recordSetVar="contacts">
        <apex:pageBlock title="Contacts List">
            
            <!-- Contacts List -->
            <apex:pageBlockTable value="{! contacts }" var="ct">
                <apex:column value="{! ct.FirstName }"/>
                <apex:column value="{! ct.LastName }"/>
                <apex:column value="{! ct.Email }"/>
                <apex:column value="{! ct.Account.Name }"/>
            </apex:pageBlockTable>
            
        </apex:pageBlock>
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    应打开一个新窗口,显示标准Salesforce页面标题和侧栏元素以及联系人列表。

    A list of contacts from the standard list controller

使用标准列表控制器与使用标准控制器非常相似。首先在<apex:page>组件上设置standardController属性,然后在同一个组件上设置recordSetVar属性。标准控制器属性设置对象使用,就像标准控制器一样。 recordSetVar设置要创建的变量的名称与记录的集合,在这里{!联系人}。按照惯例,这个变量通常被命名为对象名称的复数。

<apex:pageBlockTable>是一个迭代组件,用于生成一个数据表,并附有平台样式。这是表格标记中发生的事情。

  • 将<apex:pageBlockTable>的值属性设置为由标准列表控制器加载的变量{!联系人}。这是<apex:pageBlockTable>将使用的记录列表。
  • 对于该列表中的每个记录,一次一条记录<apex:pageBlockTable>将该记录分配给<apex:pageBlockTable>的var属性中指定的变量。在这种情况下,该变量被命名为ct。
  • 对于每个记录,<apex:pageBlockTable>使用由<apex:pageBlockTable>主体内的<apex:column>组合集定义的行在表中构造一个新行。 <apex:column>组件依次使用表示当前记录的ct变量来提取该记录的字段值。
  • 在循环之外,<apex:pageBlockTable>使用<apex:column>组件中的字段通过查找每个字段的标签来创建列标题。

这是非常重要的,迭代组件是第一次很难理解。你现在可以做的最好的事情是尝试创建你自己的。选择你想在表格中显示的字段。查找<apex:pageBlockTable>和<apex:column>的不同属性,并进行试验,直到您感觉舒适。您也可以尝试使用其他一些迭代组件,例如<apex:dataList>甚至是<apex:repeat>。

添加列表视图过滤到列表

使用 {! listViewOptions}来获取可用于对象的列表视图过滤器的列表。使用 {! filterId}设置列表视图过滤器用于标准列表控制器的结果。
标准列表控制器提供了许多可用于更改列表显示的功能。其中最强大的是列表视图过滤器。您可以声明式地创建列表视图过滤器,使用点击代替代码,标准列表控制器允许您使用页面上任何已定义的列表视图过滤器。

  1. 将整个<apex:pageBlock>包装在<apex:form>标记中。
    要更改标准列表控制器的列表视图过滤器,您需要将新值提交回服务器。执行此提交的标准方法是使用使用<apex:form>组件创建的表单。
  2. 在<apex:pageBlock>标签中添加以下属性。
    id="contacts_list"
    这给了<apex:pageBlock>一个“名字”,我们可以使用它来获得一个很酷的Ajax效果,我们稍后会解释一下。
  3. 打开<apex:pageBlock>标记后,在<apex:pageBlockTable>上方,添加以下标记。
    Filter: 
    <apex:selectList value="{! filterId }" size="1">
        <apex:selectOptions value="{! listViewOptions }"/>
        <apex:actionSupport event="onchange" reRender="contacts_list"/>
    </apex:selectList>
    您的页面的完整代码应该是这样的。
    <apex:page standardController="Contact" recordSetVar="contacts">
        <apex:form>
    
            <apex:pageBlock title="Contacts List" id="contacts_list">
            
                Filter: 
                <apex:selectList value="{! filterId }" size="1">
                    <apex:selectOptions value="{! listViewOptions }"/>
                    <apex:actionSupport event="onchange" reRender="contacts_list"/>
                </apex:selectList>
    
                <!-- Contacts List -->
                <apex:pageBlockTable value="{! contacts }" var="ct">
                    <apex:column value="{! ct.FirstName }"/>
                    <apex:column value="{! ct.LastName }"/>
                    <apex:column value="{! ct.Email }"/>
                    <apex:column value="{! ct.Account.Name }"/>
                </apex:pageBlockTable>
                
            </apex:pageBlock>
    
        </apex:form>
    </apex:page>
    一个新的过滤器控件出现在列表上方。
    Contacts list with list views filter
  4. 从菜单中选择一个不同的过滤器。联系人列表发生了什么?

从刚刚创建的“滤镜”菜单中进行新选择时,应该注意两点。首先,当您选择一个新的过滤器时,记录列表会发生变化。 (您可能需要尝试几个不同的选项,在标准DE组织中使用示例数据时,某些列表视图将显示相同的记录。)

其次,更微妙的是,该列表正在更新,无需重新加载整个页面。这个“Ajax”效果是由<apex:actionSupport>组件中的reRender =“contacts_list”属性提供的。组件和reRender的联合作用是仅更新reRender属性中指定的页面部分。由于您已将id =“contacts_list”添加到<apex:pageBlock>,因此操作完成后,只更新<apex:pageBlock>,而不重新加载整个页面。

此页面上新功能的完整生命周期就像这样。

  • 当页面加载时,<apex:selectList>通过从{!中获取列表来构建可用过滤器的菜单。 listViewOptions}表达式。 listViewOptions是由标准列表控制器提供的属性。
  • 当您从菜单中选择新选项时,onchange:event将由<apex:actionSupport>组件触发。
  • 当onchange激发时,页面通过将新项目提交给在<apex:selectList>中设置的filterId属性来提交选定的新列表视图。
  • 当属性更新时,页面从服务器获得一个新的响应,在contacts变量中有一个新的匹配记录集合。
  • 但是因为<apex:actionSupport>指定仅渲染页面的一部分,所以页面使用Ajax异步JavaScript更新,而不是整页重新加载。

最终结果是,只需添加几行标记即可获得复杂而复杂的行为。

将分页添加到列表中

使用标准列表控制器的分页功能,允许用户一次查看一个“页面”的长记录列表。
到目前为止,您开发的功能非常好,并且可以很好地处理在Developer Edition组织中作为样本数据提供的记录的简短列表。但是当你拥有一个真正的组织,拥有数百甚至数千甚至数百万条记录时会发生什么?在一个页面上查看它们并不是很好!

实际上,默认情况下,标准列表控制器仅显示符合过滤条件的前20条记录(如果有的话)。你怎么能让人们访问超过前20条记录,或每页更多的记录,而不仅仅是20?

答案是分页。这是一个标准的Web应用程序用户界面元素,它允许您一次使用“下一个”和“上一个”链接一次向前和向后浏览一长串记录,即“页面”。您可以使用标准列表控制器将其添加到您的页面,以及方便程度(如进度指示器和菜单)来更改每页的记录数。

  1. 在联系人列表<apex:pageBlockTable>下方,添加以下标记。
    <!-- Pagination -->
    <table style="width: 100%"><tr>
    
        <td>
            <!-- Page X of Y -->
        </td>            
    
        <td align="center">
            <!-- Previous page -->
            <!-- Next page -->
        </td>
        
        <td align="right">
            <!-- Records per page -->
        </td>
    
    </tr></table>
    
    这将创建一个HTML表格,它将包含要添加的三个分页控件。

    注意

    在真实的网页中,您可能会使用更多的语义标记和单独的样式,但是现在,简单的HTML是简洁明了的。

  2. <!– Page X of Y –>替换为以下标记
    Page: <apex:outputText 
        value=" {!PageNumber} of {! CEILING(ResultSize / PageSize) }"/>
    这会将进度指示器添加到列表中,指示用户正在查看哪个页面,以及有多少人在那里。如果你在DE组织中尝试这个,可能会说“第1页,共1页”。
  3. 用下面的标记替换<! – 上一页 – >和<! – 下一页 – >注释行。
    <!-- Previous page -->
    <!-- active -->
    <apex:commandLink action="{! Previous }" value="« Previous"
         rendered="{! HasPrevious }"/>
    <!-- inactive (no earlier pages) -->
    <apex:outputText style="color: #ccc;" value="« Previous"
         rendered="{! NOT(HasPrevious) }"/>
    
    &nbsp;&nbsp;  
    
    <!-- Next page -->
    <!-- active -->
    <apex:commandLink action="{! Next }" value="Next »"
         rendered="{! HasNext }"/>
    <!-- inactive (no more pages) -->
    <apex:outputText style="color: #ccc;" value="Next »"
         rendered="{! NOT(HasNext) }"/>
    这个标记提供页面上的上一个和下一个链接。标记包含两种可能性:当在给定方向上有更多记录要查看时,则链接处于活动状态;并且当给定方向上没有更多页面时,该链接被禁用。
  4. 用下面的标记替换<! – 记录每页 – >注释行。
    Records per page:
    <apex:selectList value="{! PageSize }" size="1">
        <apex:selectOption itemValue="5" itemLabel="5"/>
        <apex:selectOption itemValue="20" itemLabel="20"/>
        <apex:actionSupport event="onchange" reRender="contacts_list"/>
    </apex:selectList>
    这个标记提供了一个菜单来改变每页记录的数量。这里我们只添加了一个选项,可以在页面上显示更少的记录。从列表中选择“5”,看看列表和其他控件发生了什么。
结果是一个列表页面,具有相当多的标准列表控制器提供的功能。

Contacts list with pagination controls

在进度指示器中,有三个属性用于指示有多少页:PageNumber,ResultSize和PageSize。最后两个实际用于公式表达式,将数字四舍五入到最接近的整数。这可以防止指标说一些无意义的东西,比如“1.6的第2页”。

在分页控件中,<apex:commmandLink>组件引用标准列表控制器Previous和Next提供的两个操作方法。结果是执行“上一个”或“下一个”操作的链接。

但是,这个呈现的属性是什么,有如{! HasPrevious}?这是Visualforce使您能够有条件地显示组件的方式,也就是说,取决于布尔表达式的结果。这里的页面标记是引用由标准列表控制器HasPrevious和HasNext提供的布尔属性,它让你知道在给定的方向上是否有更多的记录。通过在呈现属性中使用表达式,可以在页面上显示或隐藏该组件的结果。这是上次链接在第一次加载页面时变灰的方法,但是如果您通过单击“下一步”链接前进,则“前一个”链接变为活动状态。

每个页面选择菜单的记录使用了前面使用过的<apex:selectList>,但不是调用控制器方法来获取菜单值,而是使用<apex:selectOption>元素来获取所需的值。同样,<apex:actionSupport>标签会导致菜单在所选值更改时触发其操作,并且会再次使用reRender =“contacts_list”更新<apex:pageBlock>。这里的新部分是<apex:selectList>设置标准列表控制器的PageSize属性。

告诉我更多…

标准列表控制器提供了许多在网络应用程序中常见的功能,这里已经涵盖了许多功能。
例如,除了一次往回移动一页的“上一页”和“下一页”操作之外,还有第一个和最后一个操作将转到记录列表的开头或结尾。

在标记的背后,标准列表控制器基于StandardSetController Apex类。您可以在Force.com Apex Code开发人员指南中阅读更多关于它以及它提供的所有功能。

房间里有一头小象,我们在这里创建的例子,它的名字是排序。通常需要为列表设置默认的排序顺序,并且还需要具有排序影响的列标题,以便您即时更改排序顺序。简单的事实是,您无法单独使用Visualforce来影响排序顺序。尽管支持排序和可点击列标题所需的附加Visualforce标记和Apex代码量并不是很大,但它确实需要自定义代码。查看一些起点的附加资源。

Salesforce Visualforce (基础6)输入数据

学习目标

完成本单元后,您将能够:

  • 解释Visualforce表单的基本要求。
  • 使用不包含平台视觉样式的Visualforce表单元素进行区分。
  • 列出四个或更多的标准输入表单标签。
  • 创建一个Visualforce窗体来编辑和保存一条记录。

Visualforce表单介绍

创建和编辑数据是任何应用程序的基本方面。 Visualforce提供了您需要的所有功能,可以轻松创建可创建新记录或检索记录,编辑其值并将更改保存回数据库的页面。
在这里,我们将标准控制器与<apex:form>组件和一些易于理解的表单元素结合起来,创建一个相当复杂的记录编辑页面。

创建一个基本表单

使用<apex:form>和<apex:inputField>创建一个页面来编辑数据。将<apex:commandButton>与标准控制器中内置的保存操作组合起来,以创建新记录或将更改保存到现有记录。

让某人编辑和更新记录的页面需要执行以下所有操作。

  • 查找记录以便从数据库中进行编辑和检索。
  • 把相关的记录数据以编辑的形式放在页面上。
  • 通过更改的数据接收表单提交。
  • 验证新的值。
  • 将有效的更改保存回数据库。
  • 向提交更改的人员提供适当的消息,无论新数据是成功保存还是存在错误。

当您使用标准控制器和<apex:form>组件时,Visualforce会自动为您执行大部分这些操作。

让我们从基础开始。

  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入AccountEdit作为页面名称。
  2. 在编辑器中,用以下替换标记。
    <apex:page standardController="Account">
        
        <h1>Edit Account</h1>
        
        <apex:form>
        
            <apex:inputField value="{! Account.Name }"/>
            
            <apex:commandButton action="{! save }" value="Save" />
        
        </apex:form>
        
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    一个新的窗口应该打开,显示一个形式与一个单一的空领域的身体。
  4. 在预览窗口中,将客户的ID添加到URL,然后按ENTER。
    URL应该是这样的: https://SalesforceInstance/apex/AccountEdit?core.apexpages.request.devconsole=1&id=001D000000JRBes

    您现在应该在表单字段中看到该客户的名称。

    A basic form to edit account name

    这验证你已经有了标准的控制器工作和一个有效的记录ID。

它看起来可能不是很多,但是在六十多行标记中,您已经获得了用于更新客户名称的完整功能表单。给它一个旋转!

这些是这种形式要理解的基本方面。

  • 该页面使用<apex:page>组件中定义的客户的标准控制器。
  • <apex:form>是一个Visualforce组件,它将其中的所有内容打包成可以作为页面操作的一部分发送回服务器的东西。如果您需要将数据发送回Salesforce,大部分时间您都会在<apex:form>中执行此操作。
  • <apex:inputField>为与其关联的记录数据字段创建屏幕表单字段。您可以通过提供一个表达式来引用value属性中的相关字段。这里的表达是{! Account.Name},你应该没有困难猜测客户的名称字段。
  • 最后,<apex:commandButton>在页面的用户界面上添加一个按钮。这个按钮点击时触发一个动作。在这种情况下,该操作是标准控制器中的save()操作方法。与<apex:inputField>类似,通过引用提供给<apex:commandButton>操作属性的表达式中要调用的操作方法,可以将<apex:commandButton>与其操作连接起来。

添加字段标签和平台样式

在<apex:pageBlock>和<apex:pageBlockSection>标签中放置表单元素进行组织和分组,并使表单采用平台视觉风格。
让我们修改你的表格,使它看起来更熟悉。
  1. 在<apex:form>组件的内部,将两个表单元素包装在<apex:pageBlock>和<apex:pageBlockSection>标记中,以便您的标记看起来像这样。
    <apex:page standardController="Account">
        <apex:form>
        
        <apex:pageBlock title="Edit Account">
    
            <apex:pageBlockSection>
                <apex:inputField value="{! Account.Name }"/>        
            </apex:pageBlockSection>
    
            <apex:pageBlockButtons>
                <apex:commandButton action="{! save }" value="Save" />        
            </apex:pageBlockButtons>
    
        </apex:pageBlock>
        
        </apex:form>
    </apex:page>
    这个版本的表单的样式是完全不同的!与输出组件一样,当您在<apex:pageBlock>和<apex:pageBlockSection>标签中使用输入组件时,它们将采用平台视觉样式。
  2. 在客户名称字段下方,添加三个字段,以便您的标记看起来像这样。
    <apex:pageBlockSection columns="1">
        <apex:inputField value="{! Account.Name }"/>
        <apex:inputField value="{! Account.Phone }"/>        
        <apex:inputField value="{! Account.Industry }"/>        
        <apex:inputField value="{! Account.AnnualRevenue }"/>
    </apex:pageBlockSection>
    现在你有了一个更完整,更现实的形式来使用。
    Edit account form with platform styling

<apex:inputField>组件根据标准或自定义对象字段的类型呈现适当的输入小部件。例如,如果您使用<apex:inputField>标记显示日期字段,则日历小部件将显示在表单上。如果您使用<apex:inputField>标签来显示选取列表字段,就像我们在这里为行业字段所做的一样,则会显示一个下拉列表。

<apex:inputField>可用于捕获任何标准或自定义对象字段的用户输入,并且尊重在字段定义上设置的任何元数据,例如字段是必需的还是唯一的,或者当前用户是否有权查看或编辑它。

显示表单错误和消息

使用<apex:pageMes​​sages>显示任何表单处理错误或消息。
出现问题时,您的页面应提供有用的反馈,例如缺少必填字段或字段值未通过验证时。标准控制器实际上为您处理所有这些。所有你需要做的是告诉它在哪里把信息放在页面上。
  1. 在<apex:pageBlock>标记下,添加以下行。
    <apex:pageMessages/>
  2. 尝试删除客户的名称,并用空白名称保存记录。

    显示页面的验证错误。

    Edit account with page error messages

正如你所看到的,<apex:inputField>显示了它自己的字段的错误,但是对于更长的表单来说,将页面的所有错误列在页面顶部的一个地方是一个很好的方法。

标准的控制器已经收集了表格处理后的所有页面的消息。 <apex:pageMes​​sages>组件使您能够在合适的地方显示这些消息。

告诉我更多…

显然还有很多东西需要学习如何为您的Web应用程序构建有用的可用表单。
对于初学者,Visualforce提供了十几个输入组件,而不仅仅是<apex:inputField>。 <apex:inputField>与标准控制器配合使用,可直接编辑记录数据。对于使用自定义控制器代码的页面,或者表单输入不直接映射到记录上的字段时,您需要了解其他一些信息。大多数这些组件的名称都以“apex:input”开头,您可以在组件参考中找到它们。对于选择列表和单选按钮控件,请查找名称以“apex:select”开头的组件。

对于准备在移动设备上使用的用户界面,您需要查看专门用于HTML5页面的<apex:input>,并允许您使用各种功能来生成输入用户元素移动友好。

您在此处编写的代码使用标准控制器为页面提供的许多操作。我们把这些标准的行动称为,其中也有不少。有一个核心集合可用于标准控制器的所有对象,但许多内置的标准对象还有其他可供使用的操作。

说到行动,您可以添加操作来编辑和删除现有的相关联系人。你如何添加创建新的相关联系人的能力?这不像使用创建动作创建链接那样简单,就像编辑和删除一样。这是因为这些操作对现有记录起作用,这些记录与相关客户已经有关系。但是当你创建一个新的记录时,你需要自己创建这个关系。这将要求你写一些你自己的自定义控制器代码。

Salesforce Visualforce (基础5)显示记录

学习目标

完成本单元后,您将能够:

  • 解释粗粒度和细粒度组件之间的区别,以及为什么您可能需要使用其中一个或另一个。
  • 解释什么是迭代组件,以及它的用途。
  • 使用相关的粗粒度组件显示记录详细信息和相关列表。
  • 使用相关的细粒度组件来替换和定制粗粒度组件。

输出组件简介

Visualforce包含近150个内置组件,您可以在页面上使用它们。请求页面时,组件呈现为HTML,CSS和JavaScript。粗粒度的组件在一个单独的组件中提供了大量的功能,并且可能为它所使用的页面添加了大量的信息和用户界面。细粒度的组件提供了更加专注的功能,并使您能够设计页面,使其看起来和行为符合您的需要。
在这里,我们将重点讨论输出组件,也就是从记录中输出数据的组件,并使您能够设计一个仅供查看的用户界面。


用标准控制器创建一个Visualforce页面

将输出组件与标准控制器一起使用,以便于访问和显示记录详细信息。
您将在此页面中尝试多个不同的输出组件。现在,让我们创建一个大部分空白的页面。

  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入页面名称的AccountDetail。
  2. 在编辑器中,用以下替换标记。
    <apex:page standardController="Account">
        
        {! Account.Name }
        
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    应打开一个新窗口,显示标准的Salesforce页面标题和侧边栏元素,但没有任何内容。
  4. 在预览窗口中,将帐户的ID添加到URL中,然后按回车键。
    该URL应该是这样的:https://SalesforceInstance/apex/AccountDetail?core.apexpages.request.devconsole=1&id=001D000000JRBes
    您现在应该在正文中看到该帐户的名称。这验证你已经有了标准的控制器工作和一个有效的记录ID。

显示记录详情

使用<apex:detail>快速将记录详细信息添加到使用标准控制器的页面。
一些输出组件给聚会带来了很多。这些“粗粒度”组件提供了许多功能,显示许多字段,标签和其他用户界面元素。它们使您可以快速构建内置Salesforce用户界面的变体页面。

  1. 将行替换为{! Account.Name},使用以下标记,并保存您的更改。
    <apex:detail />
    哇,这是一个很大的改变!使用一行标记,您可以复制帐户对象的整个标准视图页面!
    The <apex:detail/> component

<apex:detail>是一个粗粒度输出组件,它只在一行标记中向页面添加许多字段,部分,按钮和其他用户界面元素。还要注意,它添加到页面的所有内容都使用Salesforce Classic样式。定制<apex:detail>的外观有相当多的属性。现在花几分钟,尝试改变几个看看他们做什么。要创建与Lightning Experience的风格更加一致的页面,请参阅了解Visualforce&Lightning Experience模块中的重要视觉设计注意事项。

显示个别字段

使用<apex:outputField>显示记录中的各个字段。
当你需要更多的控制你的页面布局时,你可以单独添加字段。 <apex:outputField>组件是专门为此而设计的。

  1. 用下面的标记替换<apex:detail />行。
    <apex:outputField value="{! Account.Name }"/>
    <apex:outputField value="{! Account.Phone }"/>
    <apex:outputField value="{! Account.Industry }"/>
    <apex:outputField value="{! Account.AnnualRevenue }"/>
    
    这四个字段被添加到页面。但格式化可能不是你所期望的。字段值全部显示在一行中,没有标签,也没有其他格式。这不是我们想要的,与<apex:detail>和<apex:relatedList>组件形成了鲜明的对比,这些组件自动使用平台样式。
    本身,<apex:outputField>只输出字段的值。但是,当您将其封装在<apex:pageBlock>和<apex:pageBlockSection>组件中时,其行为会发生相当大的变化。

  2. 用<apex:pageBlock>和<apex:pageBlockSection>组件包装<apex:outputField>行,以便您的标记看起来像这样。
    <apex:pageBlock title="Account Details">
        <apex:pageBlockSection>
            <apex:outputField value="{! Account.Name }"/>
            <apex:outputField value="{! Account.Phone }"/>
            <apex:outputField value="{! Account.Industry }"/>
            <apex:outputField value="{! Account.AnnualRevenue }"/>
        </apex:pageBlockSection>
    </apex:pageBlock>
    这还差不多!
    Output fields inside a page block

    需要<apex:pageBlock>和<apex:pageBlockSection>组件来激活平台外观。当在<apex:pageBlockSection>中使用<apex:outputField>时,它将采用两列布局,很好地添加字段标签,对齐和样式字段和标签等等。

    尽管<apex:outputField>看起来像一个细粒度的组件,因为它只输出一个字段,但实际上却做了很多。它知道是否在某些其他组件中使用它,并适当地更改其输出和样式。格式和显示也很聪明。请注意,年收入字段被格式化为货币。 <apex:outputField>自动适应正在显示的字段的数据类型。尝试添加一个日期,清单,或选择列表字段到页面,看看会发生什么。

显示一个表

使用<apex:pageBlockTable>将数据表添加到页面。
什么是相关列表?当您将其添加到页面时,<apex:relatedList>会执行什么操作?
  • 它抓取了一个类似数据元素的列表。例如,该帐户的联系人列表。
  • 它为每个字段设置一个列,每个列上面都有标题,等等。
  • 对于列表中的每个项目(对于每个相关联系人),它将向表格添加一行,并使用该记录中的适当字段填充每列。

您可以使用迭代组件在自己的Visualforce标记中执行相同的操作。一个迭代组件与一组相似的项目一起工作,而不是一个单一的值。例如,{!Account.contacts}是一个表达式,用于计算一个帐户的联系人列表。您可以将此表达式与迭代组件一起使用来创建列表或表格,其中包含这些相关联系人的详细信息。

  1. 用下面的标记替换两个<apex:relatedList />行。
    <apex:pageBlock title="Contacts">
       <apex:pageBlockTable value="{!Account.contacts}" var="contact">
          <apex:column value="{!contact.Name}"/>
          <apex:column value="{!contact.Title}"/>
          <apex:column value="{!contact.Phone}"/>
       </apex:pageBlockTable>
    </apex:pageBlock>
    列出帐户联系人的表格会添加到页面中,只有您选择的列。
    Contacts list using pageBlockTable
<apex:pageBlockTable>是一个迭代组件,用于生成一个数据表,并附有平台样式。这是你的标记发生了什么。

  • <apex:pageBlockTable>的值属性被设置为前面提到的表达式{!Account.contacts}。这是<apex:pageBlockTable>将使用的记录列表。
  • 对于该列表中的每个记录,一次一条记录<apex:pageBlockTable>将该记录分配给<apex:pageBlockTable>的var属性中指定的变量。在这种情况下,该变量被命名为contact。
  • 对于每条记录,<apex:pageBlockTable>使用由<apex:pageBlockTable>主体内的<apex:column>组合集定义的行在表中构造一个新行。 <apex:column>组件依次使用表示当前记录的联系变量来提取该记录的字段值。
  • 在循环之外,<apex:pageBlockTable>使用<apex:column>组件中的字段通过查找每个字段的标签来创建列标题。

这是非常重要的,迭代组件是第一次很难理解。你现在可以做的最好的事情是尝试创建你自己的。使用<apex:pageBlockTable>将与机会相关的记录列表添加到页面。选择你想在表格中显示的字段。查找<apex:pageBlockTable>和<apex:column>的不同属性,并进行试验,直到您感觉舒适。

告诉我更多…

粗粒度的组件使您可以快速地为页面添加大量的功能,而精细的组件可以让您更好地控制页面的特定细节。
<apex:enhancedList>和<apex:listViews>是您可能要用于或代替<apex:relatedList>的其他粗粒度组件。还有许多其他组件将很多功能包装到一个标签中。如果你还没有做,请查看标准组件参考,看看可能的范围。

<apex:pageBlockTable>是一个迭代组件,用于获取Salesforce Classic样式。 <apex:dataTable>和<apex:dataList>是用于创建表格和列表的迭代组件,无需创建样式。 <apex:repeat>是一个迭代组件,您可以使用它来为记录集合生成任意标记。

您可能已经注意到,手动创建的相关列表缺少一些添加到由<apex:relatedList>创建的表中的内容。例如,用于编辑和删除单个记录的编辑和删除链接缺失,新联系人按钮也是如此。要创建这些用户界面元素,您需要了解更多的Visualforce,特别是关于表单和操作。你会在其他地方了解到。

Salesforce Visualforce (基础4)标准控制器

学习目标

完成本单元后,您将能够:

  • 解释什么是Visualforce标准控制器,并描述其关键属性。
  • 将标准控制器添加到Visualforce页面。
  • 显示来自页面标准控制器检索的记录的数据。
  • 写一个表达式,使用点符号来访问相关记录上的字段。

Visualforce标准控制器介绍

Visualforce使用传统的模型 – 视图 – 控制器(MVC)范例,并包含复杂的内置控制器来处理标准动作和数据访问,与Force.com数据库提供简单而紧密的集成。这些内置控制器通常被称为标准控制器,甚至标准控制器。
MVC设计模式可以很容易地将视图和样式从底层数据库和逻辑中分离出来。在MVC中,视图(Visualforce页面)与控制器交互,控制器为页面提供功能。例如,控制器可以包含单击按钮时要执行的逻辑。控制器通常还与模型(数据库)进行交互 – 制作视图可能要显示的可用数据,或将更改推送回数据库。

大多数标准和所有自定义对象都具有标准控制器,可用于与对象相关的数据进行交互,因此您无需自己编写控制器的代码。您可以扩展标准控制器以添加新功能,或从头创建自定义控制器。在这里,您将了解到标准控制器。

查找记录ID并将其添加到请求URL

通过将请求URL中的参数添加到标准控制器,为记录提供记录标识。
如果要使用标准控制器来引用特定记录,则需要知道要使用的记录的记录标识符或标识。它使用ID来检索数据,并在记录数据更改时将其保存回数据库。

当您的Visualforce页面与组织中的其他页面进行交互时,您可以自动传入记录的标识符,Visualforce页面可以使用它查找并显示该记录的数据。但是在开发过程中,页面是独立的,所以为了让页面显示数据库记录中的数据,需要手动提供记录ID。最简单的方法是将其作为GET参数添加到请求URL中。

  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入页面名称的AccountSummary。
  2. 在编辑器中,用以下替换标记。
    <apex:page>
        
        <apex:pageBlock title="Account Summary">
            <apex:pageBlockSection>
            	
                
                
            </apex:pageBlockSection>
        </apex:pageBlock>
        
    </apex:page>
    这个标记创建一个框,为您准备添加一些有用的信息。
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    确保您可以看到预览窗口的URL字段。您将通过几个步骤回到此处。
  4. 在单独的浏览器窗口中,转至组织的主页,然后选择“帐户”选项卡。
    如果“客户”选项卡不可见,请从右上角的应用程序菜单中选择“销售”,切换到“销售”应用程序。
  5. 确保“查看”菜单显示“所有客户”,然后单击“查看”查看所有客户记录。
  6. 在“所有帐户”页面上,单击任何帐户名称。
  7. 帐户详细信息页面加载完成后,查看该页面的URL。

    该URL将如下所示:this:https://SalesforceInstance/one/one.app#/sObject/001D000000JRBes/.

    记录的标识符,它的ID是最后一系列的字母和数字。在这个例子中,它是“001D000000JRBes”(但是在你的组织中它将是不同的)。它在您组织中所有对象类型的所有记录中都是唯一的。

  8. 选择记录ID,并将其复制到剪贴板。

    在您离开帐户详细信息页面之前,请查看整个页面以及显示的信息。

    Account details page

    为了获得一个记录ID,这不是绕道而行的。在您完成之前,您将了解如何在Visualforce代码中构建一个自己显示相同信息的页面。

  9. 切换回您从Developer Console打开的预览页面。点击浏览器窗口的URL字段,在URL的末尾输入&id =,然后粘贴您之前复制的记录ID。
    该URL应该是这样的:https://SalesforceInstance/apex/AccountSummary?core.apexpages.request.devconsole=1&id=001D000000JRBes
  10. 按Return键加载新网址的页面。

尽管加载带有记录ID的预览页面看起来没有什么不同,但是添加ID意味着您现在可以通过加载该记录并使其在页面上显示来请求标准控制器帮助您。

要在Lightning Experience的上下文中预览页面,请打开浏览器的JavaScript控制台并输入以下代码。不要忘记用你的页面名称来替换pageName:

$A.get("e.force:navigateToURL").setParams(
    {"url": "/apex/pageName"}).fire();
您还可以通过以下方式预览带有记录ID的页面:将记录ID参数添加到JavaScript中URL的末尾:
$A.get("e.force:navigateToURL").setParams(
    {"url": "/apex/pageName?&id=00141000004jkU0AAI"}).fire();

显示单个记录中的数据

将帐户的标准控制器添加到页面,然后引用帐户字段以显示记录的数据。

按照以下步骤创建一个显示帐户摘要的页面。

  1. 在页面标记的开始处,在<apex:page>标记内添加以下属性。
    standardController="Account"
    当您现在保存页面时,预览页面将像以前一样重新加载,除了此时用于帐户的标准控制器处于活动状态。当页面加载时,标准控制器解析URL中的参数,找到id参数,并使用它的值来检索记录并使其可用于页面。你还看不到,但它在那里。
  2. 在页面的主体中,添加以下标记。
    Name: {! Account.name }
    繁荣。现在你可以看到记录正在被检索!您应该看到具有您添加到URL的记录ID的帐户的名称。
  3. 用以下标记替换单行与帐户名称。
    Name: {! Account.Name } <br/>
    Phone: {! Account.Phone } <br/>
    Industry: {! Account.Industry } <br/>
    Revenue: {! Account.AnnualRevenue } <br/>
    
    你的完整代码应该是这样的。
    <apex:page standardController="Account">
        
        <apex:pageBlock title="Account Summary">
            <apex:pageBlockSection>
            	
                Name: {! Account.Name } <br/>
                Phone: {! Account.Phone } <br/>
                Industry: {! Account.Industry } <br/>
                Revenue: {! Account.AnnualRevenue } <br/>
                
            </apex:pageBlockSection>
        </apex:pageBlock>
        
    </apex:page>
    结果应该是一个简单的帐户摘要。
    A simple account summary page

那么,这里发生了什么?很多,标准控制器的礼貌!

  1. 当页面被加载,并且<apex:page>组件被激活时,它激活帐户对象的标准控制器。
  2. 标准控制器可以看到URL中有一个ID参数,并搜索并检索匹配的帐户记录。
  3. 标准控制器接受记录并将其放入可供页面使用的变量中。该变量与标准控制器的sObject:Account具有相同的名称。它是一个对象变量,并包含Account sObject上可用的所有字段。
  4. 四个Visualforce表达式都引用了Account变量。他们使用“点符号”访问Account变量中的各个字段。所以,{! Account.Name}获取帐户的名称,依此类推。

但是,收入是多少?它以科学记数法显示。你怎么能把货币显示为货币呢?

数字以科学记数法显示为“原始”值的原因是因为数字是由表达式直接输出的。它将原始值直接放在页面上。要控制值的格式,您需要使用一个组件,并给组件提供值来处理。组件将采取原始值并适当格式化,然后将结果输出到页面上。你会学到如何做到这一点。这里我们只是对访问记录数据感兴趣。

 

告诉我更多…

标准的控制器是相当强大的,我们只是抓了表面。你会在别处学到更多的东西,但是这里有一些亮点。
除了这里所示的简单数据访问之外,标准控制器还提供一组标准操作,例如创建,编辑,保存和删除,您可以使用标准用户界面元素(如按钮和链接)将其添加到您的页面。当您了解有关Visualforce输入表单并将更改保存回数据库时,您将了解有关这些标准操作的更多信息。

要嵌入到对象页面布局中的Visualforce页面,作为对象特定的自定义操作使用,或者在Salesforce应用程序中用作移动卡,必须使用相关对象的标准控制器。

如果您创建了自己的自定义对象(而不是像Account一样使用对象)并且想知道如何引用字段,则必须遵循一个稍微不同的过程。从设置中,在快速查找框中输入对象,然后选择对象,选择您的对象,然后选择该字段。 API名称现在指示您必须在Visualforce页面中使用的字段的名称。例如,如果您的字段名为Foo,则其API名称为Foo__c,并且您将使用该名称引用它 – 如:{! myobject__c.foo__c}。

像标准控制器一样强大,有时你需要做一些不同的事情。这在Visualforce中没有问题。在任何时候,您都可以使用Apex代码替换或扩充它们,并编写自己的控制器或扩展到内置控制器。

Salesforce Visualforce (基础3)使用变量

学习目标

完成本单元后,您将能够:

  • 解释什么是Visualforce表达式,并描述它的用途。
  • 列出可用于Visualforce表达式的三个或更多全局变量。
  • 将Visualforce表达式添加到Visualforce页面。
  • 在Visualforce表达式中使用一个函数。

全局变量和Visualforce表达式简介

Visualforce页面可以显示从数据库或Web服务中检索的数据,根据登录的用户和查看页面而变化的数据等等。这个动态数据是通过使用由页面控制器提供的全局变量,计算和属性在标记中访问的。这些一起被描述为Visualforce表达式。使用表达式将动态输出或值传递给组件,方法是将它们分配给属性。
Visualforce表达式是可以解析为单个值的任何一组字面值,变量,子表达式或运算符。表达式中不允许使用方法调用。

Visualforce中的表达式语法是: {! expression }

任何在{! }分隔符将在页面呈现或使用时动态替换。空白被忽略。

结果值可以是一个原始(整数,字符串等),一个布尔值,一个sObject,一个控制器方法(如一个动作方法)以及其他有用的结果。

全局变量

使用全局变量访问和显示Visualforce标记中的系统值和资源。
例如,Visualforce在名为$ User的全局变量中提供有关登录用户的信息。您可以使用以下形式的表达式来访问$ User全局变量(以及任何其他字段)的字段:{! $ GlobalName.fieldName}。

  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入UserStatus作为页面名称。
  2. 在编辑器中,用以下替换标记。
    <apex:page>
        
        <apex:pageBlock title="User Status">
            <apex:pageBlockSection columns="1">
            	
                
                
            </apex:pageBlockSection>
        </apex:pageBlock>
        
    </apex:page>
    这个标记创建一个框,为您准备添加一些有用的信息。
  3. 点击 Preview 打开您的页面的预览,您可以在进行更改时查看。
  4. 在<apex:pageBlockSection>标签之间添加以下标记。
    {! $User.FirstName }
    您应该在您创建的用户状态面板中看到您的名字。
  5. 将另外两个使用$ User全局变量的表达式添加到User Status面板的标记中,以使页面如下所示。
    <apex:page>
        
        <apex:pageBlock title="User Status">
            <apex:pageBlockSection columns="1">
                
                {! $User.FirstName } {! $User.LastName } 
               ({! $User.Username })
                
            </apex:pageBlockSection>
        </apex:pageBlock>
        
    </apex:page>

{! …}告诉Visualforce,大括号内的任何内容都是动态的,并以表达式语言编写。它的值是在运行时计算和替换的,当有人查看页面时。

Visualforce表达式不区分大小写,并且{! …}被忽略。所以这些表达式都产生相同的值:

  • {! $User.FirstName}
  • {!$USER.FIRSTNAME}
  • {! $user.firstname }

公式表达式

Visualforce使您可以在表达式语言中使用更多的全局变量。它也支持让你操纵值的公式。
例如,&字符是连接字符串的公式语言运算符。
  1. 在您的UserStatus页面中,使用以下公式表达式替换名字和姓氏的单独表达式。
    {! $User.FirstName & ' ' & $User.LastName }
    这个表达式将登录的用户的名字和姓氏组合在一起,用空格分开。输出应该看起来一样。
  2. 将以下内容添加到用户信息下方的页面标记中。
    <p> Today's Date is {! TODAY() } </p>
    <p> Next week it will be {! TODAY() + 7 } </p>
    这些是使用TODAY()函数的更复杂的公式。函数是内置的计算,您可以通过名称后面的括号来识别。
    第一个表达式简单地计算当前日期,第二个表达式使用加法运算符在日期中添加七天。页面中的输出将如下所示。

    Today's Date is Thu Sep 18 00:00:00 GMT 2014
    Next week it will be Thu Sep 25 00:00:00 GMT 2014
  3. 将以下内容添加到日期表达式下面的页面标记中。
    <p>The year today is {! YEAR(TODAY()) }</p>
    <p>Tomorrow will be day number  {! DAY(TODAY() + 1) }</p>
    <p>Let's find a maximum: {! MAX(1,2,3,4,5,6,5,4,3,2,1) } </p>
    <p>The square root of 49 is {! SQRT(49) }</p>
    <p>Is it true?  {! CONTAINS('salesforce.com', 'force.com') }</p>
    您的网页上的结果将是这样的。

    Visualforce expressions playground

    一些函数,如TODAY(),有一个空括号,但有些函数需要函数用来计算的参数。在这个例子中,YEAR()接受一个由TODAY()函数提供的日期参数,它不带任何参数。 MAX()函数可以使用任意数量的参数。

    CONTAINS()函数特别有趣。它返回一个布尔值:true或者false。它比较文本的两个参数,如果第一个参数包含第二个参数,则返回true。如果不是,则返回false。在这种情况下,字符串“force.com”包含在字符串“salesforce.com”中,所以它返回true。

条件表达式

使用条件表达式根据表达式的值显示不同的信息。
例如,如果发票没有订单项,则可能需要显示单词“none”而不是空白列表。或者,如果某个项目已过期,则可能需要显示“已结束”,而不是显示结束日期和时间。
您可以使用条件公式表达式(如IF())在Visualforce中执行此操作。 IF()表达式有三个参数:

  • 首先是一个布尔值:不管是真还是假。例如,您以前使用的CONTAINS()函数。
  • 第二个参数是第一个参数为true时返回的值。
  • 第三个参数是第一个参数为false时将返回的值。
  1. 在您的UserStatus页面的其他表达式下面,添加以下代码。
    <p>{! IF( CONTAINS('salesforce.com','force.com'), 
         'Yep', 'Nope') }</p>
    <p>{! IF( DAY(TODAY()) < 15, 
         'Before the 15th', 'The 15th or after') }</p>

    在保存更改并查看结果之前,尝试预测它们将会是什么!
    第一个表达式使用与以前相同的CONTAINS()函数计算。 IF()函数将CONTAINS()的布尔结果转换为更有用的显示给用户的文本。同样,第二个表达式在本月上半月显示一条消息,在本月下半月显示另一条消息。

  2. 删除所有的测试表达式,只留下使用$ User全局变量的行。
    换句话说,回到这个页面。

    <apex:page>
        
        <apex:pageBlock title="User Status">
            <apex:pageBlockSection columns="1">
                
                {! $User.FirstName & ' ' & $User.LastName } 
               ({! $User.Username })
                
            </apex:pageBlockSection>
        </apex:pageBlock>
        
    </apex:page>
    让我们使用条件表达式来做一些更有用的事情。
  3. 用以下代码替换$ User.Username表达式的行。
    ({! IF($User.isActive, $User.Username, 'inactive') })
    
    isActive是$ User全局变量上可用的另一个字段。这是一个布尔字段,如果用户处于活动状态,则为true;如果已停用,则为false。现在,“用户状态”面板将显示用户的用户名(如果它们处于活动状态),如果不是,则显示“不活动”(inactive)。

告诉我更多…

在Visualforce表达式中可以使用许多全局变量和函数。
Visualforce中可以使用近二十个全局变量。如您所见,它们对于获取有关当前登录用户的信息非常有用,但也可用于获取有关组织($ Organization),设置($ Setup),有关自定义对象的详细信息($ ObjectType)的详细信息,对象($ Action)等等。请参阅Visualforce全局变量参考。

同样,在Visualforce中可以使用几十个函数。该列表与公式字段中的可用功能类似,但不完全相同。在它们重叠的地方,函数的行为是相同的,所以在编写Visualforce表达式时,可以重复使用大部分关于公式字段的知识。请参阅Visualforce函数参考以获取完整列表。

表达式有许多用途,常常用于为Visualforce组件上的属性提供值。