You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 11:38:09