異常或者error code匯總:https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_concepts_core_data_objects.htm
做項目的時候有很多異常是我們經常遇到的:
1.空指針異常;
2.死鎖或者超時;
3.級聯刪除時無級聯表操作權限導致刪除失敗;
4.一次請求查詢超過50000條數據;
5.查詢時偏移量超過2000;
6.不滿足Validation Rule條件;
7.必填字段為空;
8.unique字段記錄添加重復。
上述問題很多可以封裝公共方法來捕獲異常並且返回友好的提示信息,免得將異常直接拋出,導致用戶一頭霧水。
此篇針對常見異常進行最基本的封裝,方便后期項目有類似需求可以直接使用。
ErrorHelper:此類封裝的getUserFriendlyMessage方法用於當程序操作出現異常時,可以返回友好的錯誤提示信息,第一個參數是errormessage,即error.getMessage(),第二個參數為sObject的API Name。
1 global with sharing class ErrorHelper { 2 private static final String NULL_POINTER_EXCEPTION = '空指針錯誤'; 3 private static final String RECORD_ALREADY_INPROCESS = '記錄已經被鎖定'; 4 private static final String RECORD_OVER_LIMIT = '查詢最多只能50000條,請輸入搜索條件重新搜索'; 5 private static final String RECORD_OFFSET_OVER_LIMIT = '數據最多只能查詢當前檢索條件前2000條,請更改檢索條件重試'; 6 private static final String RECORD_ALREADY_IN_PROCESS = '當前記錄已經在流程中,如有問題,請與管理員聯系'; 7 public static String getUserFriendlyMessage(String msg,String sObjectName) { 8 String errorMessage; 9 //空指針錯誤:System.NullPointerException: Attempt to de-reference a null object 10 if(msg.contains('NullPointerException')){ 11 errorMessage = NULL_POINTER_EXCEPTION; 12 } 13 //死鎖或者超時 14 else if(msg.contains('UNABLE_TO_LOCK')){ 15 errorMessage = RECORD_ALREADY_INPROCESS; 16 } 17 //級聯刪除,沒有當前表或者關聯表權限導致的錯誤 18 else if(msg.contains('DELETE_REQUIRED_ON_CASCADE')) { 19 20 } 21 //查詢50001 22 else if(msg.contains('Too many query rows')) { 23 errorMessage = RECORD_OVER_LIMIT; 24 } 25 //offset 超過2000 26 else if(msg.contains('Maximum SOQL offset allowed is 2000')) { 27 errorMessage = RECORD_OFFSET_OVER_LIMIT; 28 } 29 //當前記錄已經在審批流中 30 else if(msg.contains('ALREADY_IN_PROCESS')) { 31 errorMessage = RECORD_ALREADY_IN_PROCESS; 32 } 33 //Validation Rule失敗 34 //eg: Update failed. First exception on row 0 with id a052800000BvtqEAAR; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, 商品價格不能為空且必須大於0.: [GoodsPrice__c] 35 else if (msg.contains('FIELD_CUSTOM_VALIDATION_EXCEPTION')){ 36 errorMessage = getUserFriendlyMessage4ValidationException(msg,sObjectName); 37 } 38 //必填字段 39 //eg:Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [Company_Name__c]: [Company_Name__c] 40 else if(msg.contains('REQUIRED_FIELD_MISSING')){ 41 errorMessage = getUserFriendlyMessage4RequiredField(msg,sObjectName); 42 } 43 //對於unique的字段進行相同值插入會報此種錯誤:System.DmlException: Insert failed. First exception on row 0; first error: DUPLICATE_VALUE, duplicate value found: Company_Code_Unique__c duplicates value on record with id: a032800000KOlEr: [] 44 45 else if(msg.contains('DUPLICATE_VALUE')) { 46 errorMessage = getUserFriendlyMessage4DuplicateValue(msg,sObjectName); 47 } 48 return errorMessage; 49 } 50 51 /** 52 *針對unique字段添加重復值的異常獲取友好的message 53 *@param msg : 異常信息 eg : System.DmlException: Insert failed. First exception on row 0; first error: DUPLICATE_VALUE, duplicate value found: Company_Code_Unique__c duplicates value on record with id: a032800000KOlEr: [] 54 *@param sObjectName : sObject的API Name 55 *@return 56 */ 57 private static String getUserFriendlyMessage4DuplicateValue(String msg,String sObjectName) { 58 String errorMessage = msg; 59 Integer pointer; 60 String fieldName; 61 if(!msg.contains('DUPLICATE_VALUE')) { 62 return errorMessage; 63 } 64 pointer = errorMessage.indexOf('DUPLICATE_VALUE') + 16; 65 if(pointer > -1) { 66 errorMessage = errorMessage.mid(pointer, errorMessage.length()); 67 } 68 pointer = errorMessage.indexOf('duplicates'); 69 if(pointer > -1) { 70 errorMessage = errorMessage.mid(0,pointer); 71 } 72 pointer = errorMessage.indexOf(':') + 1; 73 if(pointer > -1) { 74 fieldName = errorMessage.mid(pointer,errorMessage.length()).trim(); 75 Schema.DescribeFieldResult fieldResult = getSObjectFieldDescribeResult(sObjectName,fieldName); 76 if(fieldResult != null) { 77 fieldName = fieldResult.getLabel(); 78 } 79 } 80 errorMessage = errorMessage.mid(0,pointer) + fieldName; 81 return errorMessage; 82 } 83 84 /** 85 *針對Validation Rule的異常獲取友好的message 86 *@param msg : 異常消息 eg: Update failed. First exception on row 0 with id a052800000BvtqEAAR; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, 商品價格不能為空且必須大於0.: [GoodsPrice__c] 87 *@param sObjectName : sObject的API Name 88 *@return 返回有問題的field labe + : + error message (eg : GoodsPrice : 商品價格不能為空且必須大於0.) 89 */ 90 private static String getUserFriendlyMessage4ValidationException(String msg,String sObjectName){ 91 String errorMessage = msg; 92 Integer pointer; 93 String fieldName; 94 if (msg.contains('FIELD_CUSTOM_VALIDATION_EXCEPTION')){ 95 pointer = errorMessage.indexOf('FIELD_CUSTOM_VALIDATION_EXCEPTION,') + 34; 96 errorMessage = errorMessage.mid(pointer, errorMessage.length()); 97 } else { 98 return msg; 99 } 100 pointer = errorMessage.indexOf('\n'); 101 if(pointer > -1){ 102 errorMessage = errorMessage.mid(0, pointer); 103 } 104 pointer = errorMessage.indexOf(':'); 105 if(pointer > -1){ 106 //去除error message中的 [] 107 fieldName = errorMessage.mid(pointer + 1,errorMessage.length()-1).remove('[').remove(']').trim(); 108 errorMessage = errorMessage.mid(0, pointer); 109 } 110 if(fieldName != null) { 111 Schema.DescribeFieldResult fieldDescribeResult = getSObjectFieldDescribeResult(sObjectName,fieldName); 112 if(fieldDescribeResult != null) { 113 errorMessage = fieldDescribeResult.getLabel() + ' : ' + errorMessage; 114 } 115 } 116 return errorMessage; 117 } 118 119 120 /** 121 * 針對必填字段獲取友好的message 122 * @param msg : 異常消息 eg: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [Company_Name__c]: [Company_Name__c] 123 * @param sObjectName : sObject的API Name 124 * @return : 友好消息 eg : Required fields are missing: Company Name (field label name) 125 */ 126 private static String getUserFriendlyMessage4RequiredField(String msg,String sObjectName){ 127 String errorMessage = msg; 128 if(!errorMessage.contains('first error:')) { 129 return errorMessage; 130 } 131 Integer pointer; 132 String fieldName; 133 //獲取first error 以后的message信息 134 pointer = errorMessage.indexOf('first error:') + 12; 135 errorMessage = errorMessage.mid(pointer, errorMessage.length()); 136 if(pointer > -1){ 137 pointer = errorMessage.indexOf(',') + 1; 138 errorMessage = errorMessage.mid(pointer, errorMessage.length()); 139 } 140 141 pointer = errorMessage.indexOf(']:'); 142 if(pointer > -1){ 143 errorMessage = errorMessage.mid(0, pointer + 1); 144 } 145 fieldName = errorMessage.mid(errorMessage.indexOf('[') + 1,errorMessage.indexOf(']')-errorMessage.indexOf('[')-1).trim(); 146 if(fieldName != null) { 147 Schema.DescribeFieldResult fieldResult = getSObjectFieldDescribeResult(sObjectName,fieldName); 148 if(fieldResult != null) { 149 fieldName = fieldResult.getLabel(); 150 } 151 } 152 pointer = errorMessage.indexOf('['); 153 if(pointer > -1){ 154 errorMessage = errorMessage.mid(0, pointer); 155 } 156 errorMessage += fieldName; 157 return errorMessage; 158 } 159 160 /* 161 * 通過sObject名稱以及field名稱獲取field相關describe result信息 162 * @param sObjectName object的api name 163 * @param fieldName field的api name 164 * @return 此field的describe result 165 */ 166 private static Schema.DescribeFieldResult getSObjectFieldDescribeResult(String sObjectName,String fieldName) { 167 List<Schema.DescribeSObjectResult> sObjectResultList = Schema.describeSObjects(new String[]{sObjectName}); 168 if(sObjectResultList == null || sObjectResultList.size() == 0) { 169 return null; 170 } else { 171 Schema.DescribeSObjectResult sObjectResult = sObjectResultList.get(0); 172 Map<String,SObjectField> maps = sObjectResult.fields.getMap(); 173 Schema.SObjectField sObjectField = maps.get(fieldName); 174 if(sObjectField == null) { 175 return null; 176 } else { 177 Schema.DescribeFieldResult fieldDescribeResult = sObjectField.getDescribe(); 178 return fieldDescribeResult; 179 } 180 } 181 } 182 183 }
使用演示:
1.Unique字段插入重復
2.必填字段為空
3.Validation Rule未通過
總結:此篇主要封裝簡單的異常的友好顯示。當前很多常量都放在了程序里,建議放在custom label中,然后對相關進行translate,這樣可以保證國際化使用,否則現在language為英文可以,中文使用會有問題,有用到的可以自行優化。