美文网首页Salesforce 开发笔记
Salesforce开发教程(二)中

Salesforce开发教程(二)中

作者: Bubba_J | 来源:发表于2018-12-17 14:50 被阅读650次

      接着上一节的内容继续开始吧!

    2.4 Page

      Visual Page类似于普通Web Page,包含的内容不限于HTML、CSS、JS等资源。我们写的Visualforce Page存储在服务器端,当用户通过url访问的时候,会被渲染成普通的Web Page,供需求用户访问。
      这里大家可能会想个问题,为什么不直接使用HTML呢,其实细想一下,HTML是静态资源,而当页面需要动态加载数据的时候,就会不好使了,所以你看Visualforce Page更像Java开发中的JSP(Java Server Pages)。在这种情况下,页面需要由服务器端进行编译转换然后提供Web Page。接下来的问题就是动态的数据或者屏幕触发方法是从哪里来的呢?Salesforce中提供的方案是一个页面需要绑定一个Controller Apex 类,除此以外,还可以通过继承父类获取更多的属性,下面我们来看一下Page运行原理的示意图。

    2.4.1 Page运行原理

    VisualforcePage

      上图为Page的加载过程,大体可以分为四个步骤:
      1、客户端发起URL请求,.../apex/MyPage
      2、Salesforce会根据请求地址执行相应的页面记录(这里需要注意的是,SF作为云服务平台,那么它是怎么找到当前用户访问的资源呢,原因就在于申请的Organization是有Id记录,所以通过OrgId过滤可以命中自己所需的资源)
      3、上面提到当访问Visualforce Page时候,后台服务器会进行编译,所以当服务器看到下面这句话的时候

    <apex:page controller="MyPageController">
    

    服务器且会根据页面绑定的Apex类执行相应的逻辑,包括但不限于数据库DML操作、访问Web资源等操作。
      4、当以上操作执行完后,后台服务器会Print一个普通的HTML页面,供用户浏览。

    2.4.2 Page 组成部分

      基本的前端元素是不可少的(HTML、CSS、JS),Salesforce还提供了预制的标准组件供开发人员使用,然后当用户访问的时候,这些组件会被解释为基本的前端元素。

    2.4.3 Page Controller

      Visualforce Page开发是传统的MVC模式,页面通过与绑定的Controller进行数据、方法交互,系统内所有的标准对象与自定义对象都有一个标准的Controler,标准的Controller包含基本的保存、删除等方法,在开发过程中,如果你不仅仅需要标准Controler中的方法,更多的时候需要一些自定义的方法,那么可以通过继承标准类来添加个性化的方法。
      一般情况下我们自定义自己的类和页面来满足业务需求。类中包含页面所需的字段信息、函数方法供页面调用。

    2.4.4 Page 表达式

      Visualforce Page可以显示从数据库、Web Service等源检索出的数据,这些动态的数据可以通过页面标签加载出来,分为全局变量、计算表达式以及页面属性等,统称为Viualforce 表达式,语法形式如下:

    {! expression }
    

      可以将以上的表达是理解为值的引用{!reference},当页面加载的时候,服务器端会自定替换该变量(空格不计)。引用的值可以是基本数据类型(数值、字符串、布尔、日期\日期时间等类型)、SObject(标准对象、自定义对象)、自定义类(MyClass)、Controller方法名等。
      其中常用的全局变量包含:Action(Salesforce标准动作,比如跳转对象主页、创建、编辑、删除记录等)、Label、Profile、User(当前登陆用户信息等)。详细列表参见:全局变量,注意语法使用,比如显示登陆用户信息:

    {!$User.FirstName}
    

      针对计算表达式,支持表达式运算符号更方便的操作数据,Visualforce Page支持字符串拼接、数据函数表达式及日期时间显示等函数功能,除此以外,还提供了条件表达式(Conditional formula Expression),比如下面的IF表达式,包含包含三个参数IF(logical_test, value_if_true, value_if_false)
    检查条件是否为真,如果条件为 TRUE 则返回一个值;如果条件为 FALSE 则返回另一个值:

    <p>{! IF( CONTAINS('salesforce.com','force.com'), 
         'Success', 'Failed') }</p>
    <p>{! IF( DAY(TODAY()) < 18, 
         'Before the 18th', 'The 18th or after') }</p>
    

      如果上面的功能还满足不了需求,就需要将页面与Controller绑定,由Controller处理自定义逻辑来提供前端需要的数据。
      总之呢,VisualForce表达式将包含字面量、变量、表达式运算、内置函数的一个集合解析成单一的数值,供前端用户使用。

    2.4.5 Page的Controller方法

      Controller属性和方法是供Visualforce Page使用,页面的元素无非可以分为三类:显示数据、输入数据、执行操作,那么映射到Controller中分别对应:Gettter方法、Setter方法、Action方法,下面我们来简单说明一下这三者的使用说明:
      Getter方法会返回一个数值给到Page页面,比如在上一节提到的动态Page执行的例子,当页面解析到下面这条语句的时候,其实会去调用与这个页面绑定的Controller中的getVariable方法,这个例子中{!}中的Variable是myAccounts,所以其实调用的是MyAccountController中的getMyAccounts方法(不区分大小写),如果找不到这个方法,会提示你找不到该变量信息。

    <apex:pageBlockTable value = "{!myAccounts}" var = "account">
    

      与Getter方法相对应的方法是Setter方法,Setter方法允许用户在页面填写的表单信息赋值Controller中的变量中,一旦检测到用户页面的动作发生变化(比如保存、删除数据等操作),该方法会自动先执行,Controller中的方法名称为setVariable,如果get、set方法仅仅是简单的赋值,可以简单的用以下方式申明:

    public  Account acc{set; get;}
    

      除了变量的获取和赋值,还必须满足事件的触发执行,让莪们先来修改一下上节中的动态Page:

    public class MyAccountController{
        public Account account { get; private set; }
        public MyAccountController() {
            Id id = ApexPages.currentPage().getParameters().get('id');
            account = (id == null) ? new Account() : 
                [SELECT Name,Phone,Industry FROM Account WHERE Id = :id];
        }
         public PageReference save() {
            try {
                upsert(account);
            } catch(System.DMLException e) {
                ApexPages.addMessages(e);
                return null;
            }
            //  After successful Save, navigate to the default view page
            PageReference redirectSuccess = new ApexPages.StandardController(Account).view();
            return (redirectSuccess);
        }    
        public List<Account> getmyAccounts(){
           List<Account> accList = new List<Account>([select Id,AccountNumber,Name from account where OwnerId =:userinfo.getUserId()]);
           return accList;
        }
    }
    

                 MyAccountController.cls

    <apex:page controller="MyAccountController">
        <apex:form>
            <apex:pageBlock>
                <apex:pageMessages/>
                <apex:pageBlockSection>
                    <apex:inputField value="{!Account.name}"/>
                    <apex:inputField value="{!Account.industry}"/>
                    <apex:inputField value="{!Account.Phone}"/>                       
                </apex:pageBlockSection>
                <apex:pageBlockButtons location="bottom">
                    <apex:commandButton value="Save" action="{!save}"/>
                </apex:pageBlockButtons>
            </apex:pageBlock>
            <apex:pageBlock>
                <apex:pageBlockTable value = "{!myAccounts}" var = "account">
                    <apex:column  value = "{!account.AccountNumber}"/>
                    <apex:column  value = "{!account.Name}" />              
                </apex:pageBlockTable>
            </apex:pageBlock>
        </apex:form>
    </apex:page>
    

                 MyAccountPage.page
      之前的功能仅是显示了所有人是当前登陆用户的客户,现在添加了一个PageBolck供用户在该页面添加客户:


    预览结果

      当用户输入客户姓名、行业等信息之后,点击保存按钮(事件触发),执行Controller中的save方法,跳转到刚创建的客户记录详细页面,这个过程有两个问题值得注意:
    1、当用户点击Save按钮后,执行了后台的Controler方法,那么表单什么时候提交的?其实在你点击Save方法时,sf会先执行Set方法,然后再执行你调用的方法。
    2、VF页中支持执行后台方法的标签有哪些呢?
      提交表单、表单计算等操作使用<apex:commandButton>

    <apex:commandButton action="{!save}" value="Save" id="theButton"/>
    

      刷新页面、导航栏指引等使用<apex:commandLink>

    <apex:commandLink action="{!refresh}" value="Refresh" id="theCommandLink"/>
    

      需要在JS中调用Controller方法时,使用<apex:actionFunction> ,JS中调用的方法名称是name的值。

     <apex:actionFunction name="clearList" action="{!clearlist}" reRender="form" />
    

    2.4.6 举例说明

      结合上一节的内容,其实我们已经可以通过SF平台做一些自己喜欢的事情了。接下来我们来完善一下上面的例子,第一阶段呢我们在浏览器端展示了自己的客户,第二阶段我们可以创建自己的客户,并且保存到了数据库,这一阶段呢我们将需要在输入客户信息点击保存Save按钮后,刷新客户列表,并且将填写的表单置空。
      1、改造Save方法,保存数据后,执行数据库插入动作,并且需要将account变量重新赋值为空。

         public void save() {
            try {
                upsert(account);
                account = new Account();
            } catch(System.DMLException e) {
                ApexPages.addMessages(e);
            }        
        }  
    

      2、局部刷新第二个PageBlock内容列表,修改VF页面如下:

            <apex:pageBlock>
                <apex:pageMessages/>
                <apex:pageBlockSection>
                    <apex:inputField value="{!Account.name}"/>
                    <apex:inputField value="{!Account.industry}"/>
                    <apex:inputField value="{!Account.Phone}"/>                       
                </apex:pageBlockSection>
                <apex:pageBlockButtons location="bottom">
                    <apex:commandButton value="Save" action="{!save}" reRender = "myAccounts"/>
                </apex:pageBlockButtons>
            </apex:pageBlock>
            <apex:pageBlock id = "myAccounts">
                <apex:pageBlockTable value = "{!myAccounts}" var = "account">
                    <apex:column  value = "{!account.AccountNumber}"/>
                    <apex:column  value = "{!account.Name}" />              
                </apex:pageBlockTable>
            </apex:pageBlock>
    

      着重强调一下reRender 属性,reRender作用是刷新局部表单数据,局部指的是DOM中的Id,通过传递给reRender参数Id,然后起到局部刷新的作用,比如上面的例子,定义了第二个PageBlock IdmyAccounts,所以当我执行完Save方法后,会自动触发该模块数据更新(实则利用Ajax重新调用了一遍getmyAccounts方法),与这个属性可能还经常一块出现的是Rendered 、renderAs,感兴趣的同学可以参考: Difference between Render, reRender and renderAs

    2.5 SOQL&DML

      在开发过程中,不可缺少的一个过程是程序需要和数据库进行交互操作(CRUD),在Salesforce平台上,查询数据常用的是SOQL(Salesforce Object Query Language)


    SOQL提取数据的过程

      语法与SQL类似,支持Where、Group、Order by、Like等语法,示例:

    SELECT Id, Name
    FROM Account
    WHERE Name  Like '%Sandy' 
    

      但是SQL的高级语法不支持,比如左连接、右连接等。其实如果你了解Salesforce表之间的关系,SQOL自身的子查询、父查询可以满足大部分业务。

    SOQL Is Powerful
      注意上图分为三个部分,目前只需要看Apex + SOQL部分,通过Apex与SOQL结合,可以查询返回逻辑层需要的所有数据(包括业务数据、配置数据等)。

    2.5.1 语法说明

    SELECT fieldList [subquery][...]
    [TYPEOF typeOfField whenExpression[...] elseExpression END][...]
    FROM objectType[,...] 
        [USING SCOPE filterScope]
    [WHERE conditionExpression]
    [WITH [DATA CATEGORY] filteringExpression]
    [GROUP BY {fieldGroupByList|ROLLUP (fieldSubtotalGroupByList)|CUBE (fieldSubtotalGroupByList)} 
        [HAVING havingConditionExpression] ] 
    [ORDER BY fieldOrderByList {ASC|DESC} [NULLS {FIRST|LAST}] ]
    [LIMIT numberOfRowsToReturn]
    [OFFSET numberOfRowsToSkip]
    [FOR {VIEW  | REFERENCE}[,...] ]
          [ UPDATE {TRACKING|VIEWSTAT}[,...] ]
    

      1、Select、From、Where、Order by、Limit
      比如查找客户以及客户下面所有的联系人:

    SELECT Account.Name, (SELECT Contact.LastName FROM Account.Contacts)
    FROM Account
    

      注意以上例子返回两个字段:客户名称、客户下面联系人的Lastname,这里用到了子查询;如果添加过滤条件,使用where,常用到的比较运算符=、!=、>、<、Like(支持模糊匹配)等以及逻辑符号And、OR等;比如上述例子想要返回客户名称为Bubba的列表:

    SELECT Account.Name, (SELECT Contact.LastName FROM Account.Contacts)
    FROM Account
    WERE NAME = 'Bubba'
    

      在实际开发中,可能还会用到给SOQL传递一个变量(Inline SOQL),要将返回的数据存到到List<Account> accList中:

    String myName = 'Bubba'
    List<Account> accList = new List<Account>([SELECT Account.Name, (SELECT Contact.LastName FROM Account.Contacts)
    FROM Account
    WERE NAME =:myName]);
    

      其他常用到的语句还有Order By、Limit等,通过Order By FieldNameList 来控制返回的结果数据顺序,多个Order By的字段名称用逗号分隔开:

    SELECT Name
    FROM Account
    ORDER BY Name DESC,INDUSTRY NULLS LAST
    

      最后的NULLS LAST指示的是如果字段为空的话,在列表的末端返回。
    注意如果查找的字段是下拉列表类型,则返回的值是api名称

    2.5.2 Group By以及其他

      下面的例子是使用Group By语句,查询系统内名称重复的客户:

    SELECT Name, Count(Id)
    FROM Account
    GROUP BY Name
    HAVING Count(Id) > 1
    

      上述例子其实也可以不需要Group By,通过单独查询客户返回到accList中,然后通过代码对accList中进行循环处理;但是用Group By之后,我们就不需要进行复杂逻辑处理,最重要的是还可以进行一些聚合函数计算,常用的有SUM()、Count()、AVG()等。
      除此以外,在SOQL数据查询中,经常会遇到处理时间类型的字段,Salesforce支持时间字面量进行筛选比如CreatedDate > 2018-12-16T10:00:00-08:00,还内置了时间函数方便开发人员。

    SELECT Name FROM Account WHERE CreatedDate > 2018-12-216T10:00:00-08:00
    SELECT Amount FROM Opportunity WHERE CALENDAR_YEAR(CreatedDate) = 2018
    

      下一部分将介绍Trigger相关内容,待续。。。

    相关文章

      网友评论

        本文标题:Salesforce开发教程(二)中

        本文链接:https://www.haomeiwen.com/subject/zkndqqtx.html