Call Apex Methods
同学们,今天咱们来聊聊在Lightning Web Components里怎么跟后端数据打交道。想象一下你有个乐高城堡,LWC就是那些五颜六色的积木,但光有积木不行,你得有图纸和材料——这就是Apex的作用。 首先,为什么需要Apex?你看,LWC本身提供了很多现成的基础组件,比如“闪电数据表”啦,“记录表单”啦,还有叫“LDS”(闪电数据服务)的适配器,它们像拧螺丝的小扳手,能搞定简单的数据读写。但有时候,你需要拧的是异形螺丝,或者你想一次性拧好多螺丝,甚至边拧边唱歌——这些基础工具就不够用了。这时候,Apex就闪亮登场了,它是你工具箱里最灵活的瑞士军刀,能写出任何你想要的复杂业务逻辑,比如跨多个对象计算佣金、集成第三方系统、或者完成一连串有条件的更新。 那么,怎么让LWC调用到Apex呢?有几个规矩得记住。第一,你写的Apex方法必须是静态的,就像班级里公用的拖把,谁都能用,而且它得用public或者global关键字公开出来。第二,必须给它贴上一个“@AuraEnabled”的标签,这就好比在拖把上写“可借出”,不然别人找不到。现在咱们有两种方式去“借”这个拖把。 第一种叫响应式调用,用@wire装饰器。想象一下,你有个自动饮水机,每次你换一桶新水,它自动就加热了。@wire就是这样,你告诉它一个Apex方法,再给它一些参数,只要参数一变,比如当前记录ID变了,它立刻重新跑去后端取最新数据,并填充到一个属性里,整个过程你都不用操心。但要记住,被@wire绑定的Apex方法必须开启缓存,也就是在注解后面加上(cacheable=true),否则它会闹脾气不工作。这种缓存能把你取回来的数据放在客户端存着,下次再要就不用跑一趟服务器了,速度飞快。 第二种叫命令式调用,像你去餐厅点菜。你喊服务员:“给我来一份宫保鸡丁!”服务员才去下单,你可以完全控制什么时候点、点完怎么做。命令式调用不受cacheable限制,所以特别适合做写入、更新、删除这些会改变数据的操作,我们把这类操作叫“突变”。调用时,你把Apex方法当作一个Promise,然后then、catch地处理结果。 参数怎么传呢?早期Salesforce是用Map传参,容易拼错键名。现在推荐直接用对象属性传,例如 { accountId: '001...', amount: 100 },这样更直观,编译器还能帮你检查。框架很聪明,它会把短时间内发起的多个Apex调用打包成像火车车厢一样,一次发出去,最多拉2500节车厢,这叫“boxcar请求”,减少了网络来回的次数,效率很高。 刚才说到缓存,如果你通过@wire拿到了数据,然后用户在页面上做了修改,数据变了,怎么让UI刷新呢?有两个贴心的小助手。一个是refreshApex(),专门用于刷新有线数据,你只需要把之前@wire生成的那个响应对象传给它,它就重新请求。另一个叫notifyRecordUpdateAvailable(),当你用命令式调用做完了增删改,LDS缓存里存的老数据就过时了,得喊一声“喂,数据更新啦!”,相关组件就会自动刷新。两者配合使用,界面就能保持最新。 有些Apex操作特别耗时,比如生成一个大报告,可能会超时。这时候可以用“延续”(Continuation),把长时间任务丢给异步处理,然后拿到一个标识,等服务器好了再回来取结果。 安全性方面绝对不能马虎。从API 67.0版本开始,Apex默认以用户模式运行,也就是严格执行当前用户的字段级安全(FLS)和对象级权限(CRUD)。以前经常需要在代码里手动加WITH SECURITY_ENFORCED,现在默认就帮你做了,省心又安全。另外,别忘了组织的共享规则也会自动应用,用户只能看见他能看的数据。 最后,错误处理。别把红通通的系统错误直接甩给用户。在Apex里,你可以用try-catch捕获异常,然后抛出一个特殊的AuraHandledException,把友好的提示信息传回去。LWC这边用catch就能拿到这个消息,温柔地展示给用户,而不是吓人的堆栈跟踪。 总结一下,Apex是LWC最强大的数据后盾,当你觉得基础组件不够用,就放心大胆地用它,记住方法要静态、公开、打注解,调用分有线自动和命令手动,传参用对象,有缓存就配refreshApex,有写入就喊notifyRecordUpdateAvailable,安全默认到位,错误温柔处理。这样,你的组件就能又聪明又强壮了。好,这讲就到这里,大家消化一下。
本课程共有 9 个章节
嗨,同学们,今天我们来聊聊在Lightning Web Components里,怎么调用Apex方法。这个话题其实挺实用的,因为咱们的组件经常需要跟后端打交道嘛。 首先呢,在JavaScript文件里,我们要通过一个特殊的导入来拿到Apex方法。这个导入用的是`@salesforce/apex`范围模块,格式是“命名空间.类名.方法名”。注意啦,这里的命名空间其实就是你组织在Salesforce里的唯一标识,比如默认的“c”或者其他自定义的。 有个容易踩的坑提醒大家:当你把Apex类名搬过来时,Salesforce的开发工具会自动帮你把类名级联改成JavaScript导入的样子,但是方法和参数的名字可不会自动变!也就是说,如果你在Apex那边改了方法名或者参数,你必须在JS代码里手动更新,不然就不匹配了,调试的时候会很头疼。 那什么样的Apex方法才能被LWC调用呢?它必须是静态的(static),访问修饰符是public或global,并且一定要带有@AuraEnabled注解。记住这三点,缺一不可。 说到具体的调用方式,我们有两种常用手段:一个是用`@wire`装饰器,另一个是命令式调用(就是直接调用函数)。如果用`@wire`,你一定得在方法定义里加上`cacheable=true`,这个很重要,因为缓存能提升性能。而且为了方便将来切换,官方也建议你在命令式调用时也加上这个属性,养成好习惯。 接下来看看允许传什么类型的数据。支持的类型挺丰富的:基础的原始类型(比如字符串、数字)、sObjects(标准或自定义对象)、Apex类的实例,还有集合(像List、Map这些)。但是要注意,不支持Apex的内部类,也不支持那个`@supressible`注解,用的时候要避开。 还有一个千万不能忽略的限制:每个调用都有自己的调用上限上下文。简单说,无论是通过`@wire`还是命令式调用,每次Apex调用都会单独消耗组织的限额。而且Salesforce框架会对一个请求里所有的Apex操作做批量处理,最多允许2500个操作。如果超过这个数,就会直接返回413错误,所以批量处理的时候得心里有数,别一次性塞太多。 最后提一下,在Salesforce DX项目里,这些Apex类放在哪儿呢?它们都在`classes`目录下,这是约定的结构。 好了,这一页的重点就是这些。弄懂这些规则,你就能顺畅地在LWC里调用Apex方法啦。下节课我们继续深入。
好,我们接着来看,如何把Apex方法和咱们组件里的属性连接起来,这是LWC里最常用的数据获取模式,非常简单,却也很容易踩坑。我一点点给你讲清楚。 首先,最简单的模式是这样的:你先从Salesforce里导入那个Apex方法,然后用`@wire`这个装饰器,直接装饰一个组件属性。比如,我写一个`accounts`属性,用`@wire(getAccountList)`去装饰它。这样一来,数据就会自动流到这个`accounts`里面。但注意,你要拿到的数据并不是直接放在属性上,而是分成了两块:一块是`accounts.data`,存着真正的数据;另一块是`accounts.error`,如果出错了,错误信息就在这儿。所以你去模板里渲染的时候,就得写`accounts.data`,并且常常要先判断一下有没有值、有没有错。 那如果Apex方法需要参数,该怎么办呢?比如我们想做一个搜索框,要根据用户输入的关键字去查数据。这就引出了“响应式”的概念。你可以在参数的位置,写一个以美元符号开头的字符串,比如`$searchKey`,它就告诉框架:嘿,我这个参数,绑定的是组件上一个叫`searchKey`的响应式属性,一旦这个属性变了,你要自动重新帮我调Apex方法,拿新数据回来。这样,你压根不用手动去调用方法,只要更新`this.searchKey`,连线就会自己动起来,非常省心。 但是,这里有一条关键语法规则,很多初学者都会在这儿栽跟头。你看到这个`$searchKey`前面的美元符号,可别以为参数就是简单传一个变量名过去。你传递给Apex方法的参数,必须是一个对象!哪怕你的Apex方法只接受一个参数,你也得把它包装成对象。比方说,Apex的方法声明是`getAccounts(String searchKey)`,那在LWC里,你不能写`@wire(getAccounts, '$searchKey')`,也不能直接把`this.searchKey`传进去。你必须写成`@wire(getAccounts, { searchKey: '$searchKey' })`。你看,外面是一个花括号,里面是这个参数的名字,冒号后面才是带美元的引用。不包这个花括号,或者直接传字符串、数组,都是不行的。这点请一定记住。 接下来,我们聊一个很实用的优化模式——去抖动,尤其是用在搜索输入框上。你想象一下,如果用户每敲一个字母,组件都立刻去服务器请求一次数据,那服务器压力得多大,网络也很浪费。正确的做法是,等用户停手不敲了,稳定一小会儿,再发请求。这个稳定的一小会儿,我们通常设成300毫秒。 怎么实现呢?我们一般在组件的属性里,用一个`setTimeout`和`clearTimeout`配合起来。比如,你有一个私有的真实存放关键词的属性`_searchKey`,然后对外使用get和set。在setter里面,你先清除上一次还没执行的定时器,然后再开一个新的定时器,延迟300毫秒,把用户刚输入的最新值赋给`_searchKey`。因为`_searchKey`被绑在`@wire`的`$searchKey`上,300毫秒后一更新,连线自然就去请求数据了。这样,无论用户打字多快,咱们只会在最后停顿之后,才发送一次请求。 这个延迟的时间通常定义成一个常量,比如`DELAY = 300`,方便统一管理。这个模式在几乎所有带搜索功能的地方,都是必选项,你用好了,组件的体验就会既流畅又轻量。 总结一下,今天咱们学了连接Apex方法和属性的核心模式:用`@wire`装饰属性,取数据用`.data`和`.error`;要传参数就用`$`前缀让它变成响应式,并且一定得包装成对象;最后,如果是搜索场景,别忘了加300毫秒的去抖动,用`setTimeout`和`clearTimeout`来延迟请求。这几点你把握住了,就能很平滑地从Apex拿数据了。
同学们,今天我们来聊聊 Lightening Web 组件里,怎么给 Apex 方法传复杂参数,以及怎么灵活处理连线调用的结果。 想象一下,你在 Apex 里定义了一个方法,需要接收一个包装好的对象作为参数,比如一个订单信息,里面包含很多字段。这时候,你会在 Apex 类里创建一个带有 @AuraEnabled 注解的类,这个类就是用来包装这些复杂参数的。 在 JavaScript 端,你需要构建一个和这个 Apex 类结构一模一样的对象,然后通过 @wire 传给对应的 Apex 方法。这里有个非常重要的点:为了保持数据的反应性,你千万不能只修改这个对象的某个属性,而是一定要整个替换它。怎么做呢?用 JavaScript 的 spread 语法,也就是三个点,复制出旧对象的所有属性,然后只修改你需要更新的那一两个字段,这样就生成一个全新的对象。这样 Salesforce 的检测机制才能知道数据变了,去重新获取数据。 接下来,很多同学会直接把 @wire 的结果绑定到一个属性上,这在简单场景下还行。但如果想要更精细地控制,比如在拿到数据后做些转换,或者处理错误,你就可以把 @wire 连到一个函数上。这个函数会自动接收一个对象,里面包含 data 和 error 两个属性。你在这个函数里,检查一下,如果有 data,就按你的需求加工一下,然后赋值给你自己定义的一个本地追踪属性;如果有 error,就赋给另一个追踪属性。这样一来,你的模板就不再直接引用 wire 的输出,而是引用你加工后的本地属性,逻辑更清晰,也好维护。 再进一步,有时候一个业务逻辑需要依赖两次服务端调用,比如先查客户,再根据客户查订单。这时候你可以用链式的 @wire。怎么做呢?很简单,把第一个 @wire 的结果(假设它叫 prop1)也设成响应式的属性,然后在第二个 @wire 的配置里,把参数写成 $prop1。这样,只要 prop1 有数据进来,第二个 @wire 就会自动重新触发,拿到对应的订单数据。如果两个结果都拿到后,你需要组合处理,那就写个公共函数,在函数里判断一下两个数据是不是都可用,再做最终的计算或展示。 好,我们总结一下今天的核心:复杂参数用包装 Apex 类,生成新对象用 spread 语法保证反应性;连到函数可以控制数据转换和错误处理;链式调用利用 $ 前缀的响应式属性,让数据流自动串联起来。这些技巧会让你的组件更健壮、更高效。大家回去可以试试看。下课!
大家好,今天我们来聊聊什么时候必须用命令式的Apex调用,以及怎么用好它。 咱们都知道,用@wire装饰器可以自动获取数据,但它有个特点:组件一加载就会执行,而且数据是通过流的方式持续推送的。可有时候,我们需要自己对调用的时机做精确控制,比如只有用户点了按钮才去请求数据。这时候就得用命令式的Apex调用了。 命令式调用会返回一个Promise,而且这个Promise只解决一次,不像@wire那样持续提供数据。那么,哪些场景必须用命令式调用呢?主要有四种: 第一种,要调用的Apex方法是不允许缓存的,比如所有涉及增、删、改的操作,像创建记录、更新数据这些,咱们都叫它TLR操作,必须用命令式。 第二种,你需要显式控制调用的时机。刚才说了,点按钮才查数据,或者表单提交时才保存,这些都得靠命令式。 第三种,Salesforce里有些标准对象是不受@wire支持的,最典型的就是Task和Event,要用它们的数据,只能走命令式。 第四种,你的代码不是写在Lightning组件里,而是普通的ES 6模块中,那个模块没有扩展LightningElement,自然没法用@wire,这也得靠命令式调用。 现在写这类调用,推荐用现代标准的 async/await 语法,再配上 try/catch 来捕获错误。写法清晰,逻辑也直观。参数传递跟@wire的规则一样,把参数包在一个普通的对象里传过去就行。 但要特别注意一个坑,千万别用JavaScript的Map对象来组装参数再传给Apex。如果你启用了LWS(Lightning Web Security),用Map传参会直接失败。记住,要用普通的JavaScript对象,花括号那种。 错误处理上,如果用async/await,就在catch块里处理;如果还用老式的Promise链,就在.catch方法里处理。不过要注意,.catch不仅能抓住Apex方法体本身抛出的错误,还能抓住前面.then处理函数里产生的异常,所以别漏了。 好了,这几条原则记牢,你就能安全、高效地使用命令式Apex调用了。下节课咱们继续深入。
大家好,今天我们来看一个非常重要的细节——Apex动作按钮的排队发送机制,还有跟它相关的@wire缓存刷新。这个机制框架会自动处理,我们感觉不到,但它对性能影响很大,所以一定要理解。 首先,当你点击按钮调用Apex方法的时候,Lightning Web Components框架不是立即一个个把请求发出去,而是会悄悄地把这些调用排好队,然后合并成一批,一次性发送到服务器。这个过程叫“boxcar”,就像把很多小车箱挂在一辆火车头上一起拉走。这样做的目的是为了尽量减少网络请求次数,提升整体性能。这个过程是透明的,我们不需要写任何代码去处理。 但要小心,如果一个页面上累积的调用数量太多,超过了2500个,服务器就会返回413错误,请求就失败了。所以如果真的遇到这种情况,你就得重新设计组件,把操作合并或者减少不必要的调用,千万别让它堆积到2500个。 接下来是@wire。用@wire装饰的Apex方法必须在方法定义里标记cacheable=true,这样它返回的数据就会被框架缓存起来。我强烈建议你在命令式调用中也尽量利用这种缓存,因为缓存的数据可以瞬间加载,用户不用等待服务器响应,体验会顺畅很多。 那么,问题来了——如果你通过命令式Apex修改了记录数据,比如更新了一个字段,那LDS(Lightning Data Service)的缓存就过时了。这时候你需要主动告诉缓存:“嘿,你的数据旧了,需要更新一下。” 怎么告诉呢?调用notifyRecordUpdateAvailable()这个方法,LDS就会知道自己持有的数据可能过时了,下次请求时会重新获取。 如果你的操作影响到了某个用@wire拿到的数据,比如你改了数据,导致某个wire的结果也跟着变了,这时候就需要用refreshApex()来手动刷新那个wire。用的时候要记住,refreshApex()会立即发起一次网络请求去拿最新的数据,所以只能在你知道缓存已经陈旧的情况下使用它。绝对不要在轮询循环里用refreshApex(),那样会每轮都发一次请求,毫无意义地消耗资源。 另外,对于用@wire装饰的函数,你要注意:这个函数被调用时会收到一个数据对象,你需要把这个对象保存下来,之后调用refreshApex()时,就把它作为参数传进去。这样框架就知道你要刷新的是哪个wire的结果。 总结一下,理解boxcar机制能帮你避免413错误,合理使用缓存和刷新方法,能让你的组件既高效又及时反映数据变化。记住这几点,你的组件就会更健壮、性能更好。
同学们,今天咱们来聊一个非常实用的小技巧,叫 getSObjectValue。 你有没有遇到过这种情况:在 Lightning Web 组件里,你调用了一个 Apex 方法,它返回了一堆 sObject 记录。看起来数据拿到了,但是有个小问题——你之前在 LDS 有线适配器里用的那个 @salesforce/schema 导入,能给你的字段引用做编译时检查、防删除、自动重命名级联,这些好处现在全没了。因为数据是直接从 Apex 返回的,不是通过 LDS 来的,编译时根本不知道你的 Apex 会返回哪些字段。 那怎么办呢?别担心,getSObjectValue 就是专为这个设计的。它让你能继续从 @salesforce/schema 导入那些字段引用,然后在跑 Apex 取回数据后,用这些引用去安全地提取值。也就是说,你写 getSObjectValue(sobject, fieldRef),它就会给你把值取出来。 这么做的好处跟原来一样:编译时就能验证字段名写没写错,万一管理员从对象上删除了这个字段,立马报错;重命名字段时,工具能自动帮你改;打包或变更集的时候也能正确包含这些字段。 而且它支持最多往下走三个层级的关系,比如 “联系人 -> 账户 -> 上级账户 -> 名称”,这样层级的关系字段也能用。 那在代码里怎么用呢?模式很简单:你把 Apex 的返回结果绑定到一个属性上,然后给每个你想要渲染的字段,写一个 getter,这个 getter 里面调用 getSObjectValue,传入数据记录和从 @salesforce/schema 导入的字段引用。最后你在模板里就像平时一样,直接绑定这些 getter 的名字就行了。 这样你就把 Apex 的灵活性和 schema 级别的严格验证结合起来啦,两全其美。你既享受了 Apex 自定义逻辑的自由,又不用牺牲编译时检查带来的安全感。 所以,记住这个小函数,等你用 Apex 返回 sObject 的时候,一定要用它来安全地访问字段值哦。
同学们,接下来我们聊聊在 Lightning Web Components 里处理长时间服务器调用时一个非常重要的机制——,Continuation,。 你可能会遇到这样的场景:从 LWC 发起一个 Apex 调用,但后端处理时间比较长,比如需要集成外部 API、做大批量数据处理,如果一直等着同步返回,用户界面就会被卡住,甚至超时报错。这时候,Continuation 就是我们的救星,它专门为这种,长时间运行的异步调用,设计,而且比普通的 `@wire` 或命令式的 `imperative` 调用更适合超时场景。 那 Continuation 到底怎么用呢?它的核心思路是:我们不直接等 Apex 返回结果,而是,先返回一个 Continuation 对象,,这个对象告诉平台“我要去干一件耗时的事,干完之后记得调用我这个组件的某个方法来处理结果”。平台会在后台执行你的请求,等就绪了再回调你指定的方法,整个过程界面不会阻塞。 具体在代码里怎么实现呢?首先,你需要在 LWC 里导入 continuation 方法,注意不是平时用的 `@salesforce/apex`,而是用 ,`@salesforce/apexContinuation`,。导入时,可以在这个注解里用空格分隔多个属性,比如 `(continuation=true cacheable=true)`,这样 Continuation 方法和回调就都可以被设置为可缓存的,支持 `@wire` 和命令式两种调用方式。 在 Apex 方法里,你需要创建一个 `Continuation` 对象,给它设置一个,回调方法名称,,也就是将来组件里用来接收结果的那个方法名。然后,你可以往这个 Continuation 对象上添加 HTTP 请求,最多可以加 ,3 个,。如果需要,还可以设置一个 `state` 属性,存放一些自定义数据,回调时原样返回给你。最后,Apex 方法必须返回这个 Continuation 对象。 平台收到 Continuation 后,会去执行那些 HTTP 请求,但每个请求的超时时间最长是 ,40 秒,(这个值实际上可以由管理员配置)。所以哪怕单个调用要跑很久,只要控制在 40 秒内,就有机会成功返回。 当平台处理完请求后,就会调用你在组件里定义的那个回调方法。这个回调方法会接收到两个参数:一个是,标签(label),,对应你之前添加的每个请求的标识,方便你区分是哪个请求返回了;另一个是,状态(status),,告诉你请求是成功还是失败了。在回调里,你可以调用 `Continuation.getResponse(label)` 来取出这个标签对应的响应数据,然后按需处理,比如赋值给组件属性或者触发后续逻辑。 最后,有几个关键限制你一定要记住: - 一个 Continuation 里最多只能添加 ,3 个 HTTP 请求,,不能更多。 - 这些请求是,客户端连续执行,的,也就是一个接一个,不会同时并发。 - 最重要的是,,在返回 Continuation 的那个 Apex 方法里,你不能使用 `@TestVisible` 或 `Test.loadData` 这类需要镜像测试资源的功能,,因为 Continuation 的返回值不会在方法体内即时生成测试数据(TLR 指的是 Test.loadData 相关限制)。 好,现在你对 Continuation 有了整体认识吧?简单概括就是:遇到长调用,先返回一个计划(Continuation),平台帮你异步跑,跑完通知你的回调来处理结果。这样既保证了用户体验,又能可靠地完成耗时任务。 下一节我们来看一个实际的代码例子,把这个流程串起来。有什么问题随时提。
同学们,今天我们来聊聊Apex代码里的安全防线。想象一下,你写的Apex方法在Lightning Web Components里被调用,如果数据保护没做好,就容易泄露不该看的信息。所以我们要掌握三道安全关卡。 ,第一道:用户访问权限。, 也就是谁能调用你的Apex类。很简单,必须通过配置文件或权限集,把类的访问权限授予当前运行的这位用户。如果他根本没权限调用这个类,代码根本跑不起来——这是最基础的“门禁”。 ,第二道:共享规则——记录级安全。, 控制的是“用户能看到哪些记录”。我们在定义类的时候可以明确声明 `with sharing`,让代码老老实实遵守组织设定的角色、共享规则,只检索用户有权查看的记录。万一用 `without sharing`,就等于绕过记录级的限制,能拿到所有记录,风险很大,一定要谨慎使用。好消息是,从API 67.0版本开始,如果什么都不写,默认就是按照共享规则运行,安全系数提高了不少。 ,第三道:对象和字段级安全,也就是CRUD和FLS。, 光能调用类、能看到记录还不够,还得管住用户能看或能改哪个字段。推荐大家在SOQL查询里直接加上 `WITH USER_MODE`,它会自动检查当前用户对这个对象和字段的访问权限,权限不够就直接报错拦截。如果某些场景下你想跳过这个检查,可以用 `WITH SYSTEM_MODE`,但这同样要特别小心。 有时候我们不想让代码粗暴报错,希望用户体验更平滑,那就可以用优雅降级的方式。`Security.stripInaccessible()` 这个方法会把查询结果里用户没有权限的字段直接“剥离”掉,剩下能看的字段照常返回,不会抛异常。剥了哪些呢?通过 `getModifiedIndexes()` 能找出被动手脚的记录,然后你可以有选择地抛出一个自定义的 `AuraHandledException`,给前端传回友好的提示信息。 最后提醒一下,过去用 `describeResult` 一点点手写 `isAccessible`、`isUpdatable` 这些检查的方式,样板代码一大堆,现在完全不推荐了。新代码请直接拥抱 `WITH USER_MODE` 或 `stripInaccessible()`,既简洁又安全。 牢记这三层防护——用户权限、共享规则、字段级安全,你在Apex里就能稳稳守住数据的底线。好了,这节课就到这里,下回见!
好,同学们,今天我们来聊聊Apex错误处理,就是当你的服务器端代码出问题的时候,怎么把合适的消息传到给用户界面,既方便调试又不会泄露敏感信息。 首先你记住,如果Apex里抛出异常但你没有主动处理,系统默认返回的东西是很详细的——完整的堆栈跟踪,类名、行号全都有。这在开发调试阶段确实很管用,一看出错位置马上就能定位。但万一这种信息跑到生产环境的用户面前,可就糟糕了,等于是把代码内部结构曝光了,不安全。 所以Salesforce给我们一个专门的类叫AuraHandledException。用它把异常包一下扔出去,客户端收到的就只有一段干净的、给用户看的消息,完全没有堆栈跟踪。这就很适合直接展示在页面上。 如果你需要自己定义一些业务上的异常类型,比如余额不足之类,你可以让你的自定义异常继承自Exception类。这样你抛出的异常既有你自己的类型,也保留了完整的堆栈跟踪——方便日志里查看,但在返回给客户端之前,还是建议包装成用户友好的消息。 还有个处理空指针的好工具,就是安全导航操作符,一个问号一个点。当你访问一个可能为null的对象属性时,用`?.`,如果它是null,就直接返回null,不会抛出让人头疼的空指针异常。 到了稍微复杂一点的项目,团队里可以约定一套标准的错误响应格式。怎么做呢?自己写一个错误包装器类,里面可以定义像severity严重程度、errorMessage错误消息等等这样的属性。这样无论哪个开发人员写接口,返回的错误结构都是一致的,前端处理起来也方便。 最后,最佳实践是:针对不同的异常类型,使用多个try-catch块分别处理。比如你可以有针对远程调用的异常、DML操作的异常、通用的异常。只捕获你预料中的错误,处理好,然后把剩下的异常传出去,让更外层的逻辑统一兜底。还有,把你的业务代码按错误处理场景拆分成不同模块,这样职责更清晰。 如果你需要实际代码参考,去GitHub上搜lwc-recipes,这个仓库里有大量Apex错误处理的示例,直接拿来看就懂了。 好了,关于Apex错误处理的要点就讲这么多,大家理解了吗?下次课我们继续。