Skip to main content

创建和使用自定义控制器

学习目标

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

  • 阐述自定义控制器的含义并描述其关键属性。
  • 创建自定义控制器类。
  • 在 Visualforce 页面中使用自定义控制器。
备注

备注

用中文(简体)学习?在中文(简体)Trailhead Playground 中开始挑战,用括号中提供的译文完成挑战。仅复制并粘贴英文值,因为挑战验证基于英文数据。如果在中文(简体)组织中没有成功通过挑战,我们建议您 (1) 将区域设置切换为美国,(2) 按此处说明将语言切换为英文,(3) 再次单击“检查挑战”按钮。

查看 Trailhead 本地化语言徽章详细了解如何利用 Trailhead 译文。

自定义控制器简介

通过在 <apex:page>  controller controller 属性中引用控制器类的名称,将自定义控制器添加到 Visualforce 页面。

当页面使用了自定义控制器时,不能再使用标准控制器。页面使用不同的属性来设置自定义控制器。

  1. 要创建新的 Visualforce 页面,请打开 Developer Console,然后单击 File(文件) | New(新建) | Visualforce Page(Visualforce 页面)。输入 ContactsListWithController 作为页面名称。
  2. 在编辑器中,将标记替换为以下内容。
    <apex:page controller="ContactsListWithController">
        <apex:form>
            <apex:pageBlock title="Contacts List" id="contacts_list">
                <!-- Contacts List goes here -->
            </apex:pageBlock>
        </apex:form>
    </apex:page>
    当您尝试保存此页面时,您会收到错误消息,原因是 ContactsListWithController 不存在。不用担心,我们接下来会解决这个问题。

创建自定义控制器 Apex 类

自定义控制器只是一个 Apex 类,您可以使用 Developer Console 自行编写。

有很多系统和实用程序类可以帮助您编写自定义控制器逻辑,但是将类用作自定义控制器的唯一要求是这个类必须存在。

  1. 要创建新的 Apex 类,请打开 Developer Console,然后单击 File(文件) | New(新建) | Apex Class(Apex 类)。输入 ContactsListWithController 作为类名称。

在编辑器中,将代码替换为以下内容。

public class ContactsListWithController {
// Controller code goes here
}

与 Visualforce 页面一样,您需要将更改的内容保存到 Apex。更改的内容并不多,而且还没有做任何事情,但 Visualforce 页面上的错误确实消失了。

  1. 切换到 Visualforce 页面并再次保存。错误提示应该会消失,并且页面已成功保存。
  2. 单击 Preview(预览)可打开页面预览,您可以在进行更改时查看该预览。此时会打开一个新窗口,显示标准 Salesforce 页面标题和侧栏元素,但尚无内容。

乍一看,您创建的这两个新项目似乎不是很有趣。但即便这两个项目 90% 都是占位符代码,Visualforce 页面和 Apex 控制器还是相互链接的。一旦向控制器添加更多代码,您的页面就可以使用控制器。

进阶学习

您可能已经注意到,这个自定义控制器类没有继承另一个类,也不承诺实现符合 Visualforce 控制器要求的接口。即使是复杂的控制器也不会执行这些操作,因为没有任何这样的类可以继承或实现接口。随着对 Apex 的逐步了解,您可以自由地创建自己的类和接口。

添加检索记录的方法

创建运行 SOQL 查询的 getter 方法,返回页面上显示的记录。

大多数控制器的主要目的是检索显示的数据,或处理数据更新。在这个简单的控制器中,您需要做的就是运行一个基础的 SOQL 查询来查找联系人记录,然后将这些记录提供给 Visualforce 页面。

  1. ContactsListWithController 类中,将 // Controller code goes here 注释行替换为以下代码。
    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 goes here --> 注释行替换为以下标记。
    <!-- 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>
    当您保存此页面时,您应该会看到一个熟悉的联系人信息表。由自定义控制器支持的联系人列表

ContactsListWithController 页面的标记看起来应该很熟悉。除了 <apex:page> 标签的 controller 属性以外,它与您使用标准控制器创建页面时使用的代码几乎相同。

区别在于评估 {! contacts } 表达式时返回的结果。在该页面上,Visualforce 将表达式转换为对控制器的 getContacts() 方法的调用。该方法返回联系人记录列表,这正符合 <apex:pageBlockTable> 的预期。

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

添加新的操作方法

在自定义控制器中创建操作方法以响应页面上的用户输入。

显示数据固然重要,但对任何网页应用来说,响应用户行为都是必不可少的。借助自定义控制器,您可以通过编写操作方法来响应用户活动,在页面上创建大量的自定义操作。

  1. ContactsListWithController 类中,在 getContacts() 方法下添加以下两种方法。
    public void sortByLastName() {
        this.sortOrder = 'LastName';
    }
    public void sortByFirstName() {
        this.sortOrder = 'FirstName';
    }
    这两种方法会更改 sortOrder 的私有变量的值。sortOrder 在检索联系人的 SOQL 查询中使用,更改 sortOrder 将更改结果的顺序。
  2. ContactsListWithController 页面中,将 ct.FirstNamect.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 属性设置为引用控制器中操作方法的表达式。(请注意,与 getter 方法相比,操作方法名称与引用操作方法的表达式相同。)

单击链接会触发控制器中的操作方法。操作方法更改私有变量的排序,然后重新显示表。重新渲染该表时,将重新评估 {! contacts },通过刚设置的排序重新运行查询。最终结果是按照用户点击请求的顺序重新排列表格。

进阶学习

名字和姓氏列的标题文本在此标记中是硬编码。但是,如果您的用户并非都使用英文怎么办?标准 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 的通用功能,并非 Visualforce 所特有。Apex 是一种完整的编程语言,它不仅是构建复杂 Visualforce 页面的天然合作伙伴,还用于多种 Lightning 平台开发环境。请参阅此处汇总的 Apex 主题,以及本页面末尾的资源,深度学习 Apex 的多种使用方法。

Visualforce 请求和响应的生命周期起初可能看起来很复杂。特别要注意的是,要清楚 getter 或 setter(使用属性的情况下)的调用没有特定的顺序,因此不能在它们之间引入执行顺序依赖关系。Visualforce 开发人员指南的相关部分提供了更多详细信息,尤其是自定义控制器和控制器扩展章节。

资源

在 Salesforce 帮助中分享 Trailhead 反馈

我们很想听听您使用 Trailhead 的经验——您现在可以随时从 Salesforce 帮助网站访问新的反馈表单。

了解更多 继续分享反馈