Salesforce Apex REST服务优化、代码改进及判空逻辑优化咨询
Salesforce Apex REST服务优化方案
针对你提供的Lead处理REST服务,从批量Upsert流程、代码结构、空值字段赋值三个维度给出具体优化方案:
一、优化批量Upsert处理流程
原代码直接对新创建的Lead对象执行Upsert,存在空值覆盖现有记录字段的风险(更新时未保留原有字段值)。优化思路是:先批量查询已存在的Lead记录,将外部传入的非空字段合并到现有记录中,再执行Upsert,确保仅更新有值的字段。
核心改进代码:
// 提取所有有效外部ID Set<String> externalIds = new Set<String>(); for(LeadDataDeserializer info : externalLeads) { if(String.isNotBlank(info.phoneNumber)) { externalIds.add(info.phoneNumber); } } // 批量查询已存在的Lead,构建外部ID到记录的映射 Map<String, Lead> existingLeadsMap = new Map<String, Lead>(); for(Lead existingLead : [SELECT Id, LastName, CountryCode__c, MobilePhone, mx_WhatsApp_Number__c, mx_IP_Address__c, Status, mx_Campaign_Name__c, SourceCampaign__c FROM Lead WHERE External_Id__c IN :externalIds]) { existingLeadsMap.put(existingLead.External_Id__c, existingLead); } // 构建待Upsert的Lead列表 List<Lead> leadsToUpsert = new List<Lead>(); for(LeadDataDeserializer info : externalLeads) { String externalId = info.phoneNumber; Lead lead = existingLeadsMap.get(externalId); // 新增场景:初始化必填字段 if(lead == null) { lead = new Lead(); lead.External_Id__c = externalId; lead.LastName = info.Name; lead.Company = 'Test Company'; } // 合并非空字段(复用后续优化的赋值逻辑) mergeLeadFields(lead, info); leadsToUpsert.add(lead); }
二、优化整体代码结构
原代码逻辑集中在单一方法内,可维护性差。优化方向是拆分职责,将请求解析、数据转换、结果封装、异常处理拆分为独立方法,同时规范命名和访问修饰符。
改进后的完整类结构:
@RestResource(urlMapping='/api/lead') global class LeadRestService { @HttpPost global static String createOrUpdateLeads() { RestResponse response = RestContext.response; try { // 1. 解析请求JSON List<LeadDataDeserializer> externalLeads = parseRequest(RestContext.request.requestBody.toString()); if(externalLeads.isEmpty()) { response.statusCode = 400; return JSON.serialize(new ServiceResponse(false, 'Empty lead list received')); } // 2. 准备待Upsert的Lead数据 List<Lead> leadsToUpsert = prepareLeadsForUpsert(externalLeads); // 3. 执行Upsert并处理结果 List<LeadUpsertResponse> upsertResponses = processUpsertResults(leadsToUpsert); // 4. 返回成功响应 response.statusCode = 201; return JSON.serialize(upsertResponses); } catch(JSONException e) { response.statusCode = 400; return JSON.serialize(new ServiceResponse(false, 'Invalid JSON format: ' + e.getMessage())); } catch(DmlException e) { response.statusCode = 400; return JSON.serialize(new ServiceResponse(false, 'DML Error: ' + e.getDmlMessage(0))); } catch(Exception e) { response.statusCode = 500; return JSON.serialize(new ServiceResponse(false, 'Internal Server Error: ' + e.getMessage())); } } // 解析请求JSON private static List<LeadDataDeserializer> parseRequest(String requestBody) { return (List<LeadDataDeserializer>)JSON.deserializeStrict(requestBody, List<LeadDataDeserializer>.class); } // 准备待Upsert的Lead数据(含现有记录合并逻辑) private static List<Lead> prepareLeadsForUpsert(List<LeadDataDeserializer> externalLeads) { Set<String> externalIds = new Set<String>(); for(LeadDataDeserializer info : externalLeads) { if(String.isNotBlank(info.phoneNumber)) { externalIds.add(info.phoneNumber); } } Map<String, Lead> existingLeadsMap = new Map<String, Lead>(); for(Lead existingLead : [SELECT Id, LastName, CountryCode__c, MobilePhone, mx_WhatsApp_Number__c, mx_IP_Address__c, Status, mx_Campaign_Name__c, SourceCampaign__c FROM Lead WHERE External_Id__c IN :externalIds]) { existingLeadsMap.put(existingLead.External_Id__c, existingLead); } List<Lead> leadsToUpsert = new List<Lead>(); for(LeadDataDeserializer info : externalLeads) { String externalId = info.phoneNumber; Lead lead = existingLeadsMap.get(externalId); if(lead == null) { lead = new Lead(); lead.External_Id__c = externalId; lead.LastName = info.Name; lead.Company = 'Test Company'; } mergeLeadFields(lead, info); leadsToUpsert.add(lead); } return leadsToUpsert; } // 合并非空字段到Lead对象(核心赋值逻辑优化) private static void mergeLeadFields(Lead lead, LeadDataDeserializer info) { Map<String, String> fieldMappings = new Map<String, String>{ 'countryCode' => 'CountryCode__c', 'phoneNumber' => 'MobilePhone', 'ipAddress' => 'mx_IP_Address__c', 'leadStage' => 'Status', 'campaignName' => 'mx_Campaign_Name__c', 'campaignSource' => 'SourceCampaign__c' // 补充剩余20个字段映射 }; Map<String, Object> infoMap = (Map<String, Object>)JSON.deserializeUntyped(JSON.serialize(info)); for(String deserializerField : fieldMappings.keySet()) { Object value = infoMap.get(deserializerField); if(value != null && String.isNotBlank(String.valueOf(value))) { lead.put(fieldMappings.get(deserializerField), value); } } // 特殊关联字段单独处理 if(lead.MobilePhone != null) { lead.mx_WhatsApp_Number__c = lead.MobilePhone; lead.External_Id__c = lead.MobilePhone; } } // 处理Upsert结果并封装响应 private static List<LeadUpsertResponse> processUpsertResults(List<Lead> leadsToUpsert) { List<LeadUpsertResponse> responses = new List<LeadUpsertResponse>(); Database.UpsertResult[] upsertResults = Database.upsert(leadsToUpsert, Lead.External_Id__c, false); for(Integer i = 0; i < upsertResults.size(); i++) { Database.UpsertResult result = upsertResults[i]; Lead lead = leadsToUpsert[i]; responses.add(new LeadUpsertResponse( result.getId(), result.isSuccess(), lead.MobilePhone, result.isSuccess() ? null : result.getErrors()[0].getMessage() )); } return responses; } // 通用错误响应类 private class ServiceResponse { public Boolean success {get; set;} public String message {get; set;} public ServiceResponse(Boolean success, String message) { this.success = success; this.message = message; } } // Upsert结果响应类 private class LeadUpsertResponse { public String leadId {get; set;} public Boolean isSuccess {get; set;} public String mobilePhone {get; set;} public String errorMessage {get; set;} public LeadUpsertResponse(String leadId, Boolean isSuccess, String mobilePhone, String errorMessage) { this.leadId = leadId; this.isSuccess = isSuccess; this.mobilePhone = mobilePhone; this.errorMessage = errorMessage; } } // JSON反序列化类 private class LeadDataDeserializer { public String Name; public String countryCode; public String phoneNumber; public String ipAddress; public String leadStage; public String campaignName; public String campaignSource; // 其他字段 } }
结构优化亮点:
- 类名、方法名语义化,可读性提升
- 逻辑拆分到独立方法,遵循单一职责原则
- 异常细分处理,返回具体错误信息
- 响应类拆分,区分通用错误和Upsert结果场景
- 内部方法用私有修饰符封装,仅暴露REST入口
三、替代大量if判空的字段赋值逻辑
原代码中20+个if判空语句重复冗余,推荐两种高效实现方案:
方案1:字段映射+反射(推荐,维护成本极低)
通过预定义字段映射表,结合反射机制循环处理所有字段,仅赋值非空内容:
private static void mergeLeadFields(Lead lead, LeadDataDeserializer info) { // 定义Deserializer字段与Lead字段的映射关系 Map<String, String> fieldMappings = new Map<String, String>{ 'countryCode' => 'CountryCode__c', 'phoneNumber' => 'MobilePhone', 'ipAddress' => 'mx_IP_Address__c', 'leadStage' => 'Status', 'campaignName' => 'mx_Campaign_Name__c', 'campaignSource' => 'SourceCampaign__c' // 补充剩余字段映射 }; // 将Deserializer对象转为Map,方便反射取值 Map<String, Object> infoMap = (Map<String, Object>)JSON.deserializeUntyped(JSON.serialize(info)); // 遍历映射表,仅赋值非空且非空白的字段 for(String deserializerField : fieldMappings.keySet()) { Object value = infoMap.get(deserializerField); if(value != null && String.isNotBlank(String.valueOf(value))) { lead.put(fieldMappings.get(deserializerField), value); } } // 特殊关联字段单独处理 if(lead.MobilePhone != null) { lead.mx_WhatsApp_Number__c = lead.MobilePhone; lead.External_Id__c = lead.MobilePhone; } }
方案2:安全导航运算符(Apex 50.0+支持)
如果你的Org支持Apex 50.0及以上版本,可使用安全导航运算符简化判空,适合字段数量较少的场景:
private static void mergeLeadFields(Lead lead, LeadDataDeserializer info) { lead.CountryCode__c = info?.countryCode; lead.MobilePhone = info?.phoneNumber; lead.mx_IP_Address__c = info?.ipAddress; lead.Status = info?.leadStage; lead.mx_Campaign_Name__c = info?.campaignName; lead.SourceCampaign__c = info?.campaignSource; // 其他字段同理 // 特殊字段处理 if(lead.MobilePhone != null) { lead.mx_WhatsApp_Number__c = lead.MobilePhone; lead.External_Id__c = lead.MobilePhone; } }
内容的提问来源于stack exchange,提问作者bnthsrikanth
相关产品推荐
相关产品推荐

