Send Custom Notifications Using REST API
前言
个人需求
当某条记录被创建后或者修改后,如果里面当内容不符合要求,那么为了增强用户体验,需要给用户发送消息提醒(Custom Notifications ),在salseforce上其实是可以使用Process Builder来发送的,也十分简单,如果有小伙伴不清楚,可以留言,我会尽快恢复。本文章使用REST API来发送Notifications,虽然代码量增多些,但是难免以后不会遇到相似的问题,因此留个笔记…
核心代码
在这之前你需要知道的是怎么才能数据肯定是以json方式发送过去,那么customNotifition的数据格式是怎样的呢?
{
"inputs" :
[
{
"customNotifTypeId" : "0MLB0000000PAwjOAG",
"recipientIds" : ["005B0000005lewTIAQ"],
"title" : "opportunity Closed!",
"body" : "Your Opportunity has been Closed.",
"targetId" : "006B00000058gHEIAY"
}
]
}
1、Get Resource From Org Use HttpRequest
/*
*Get Resource From Org Use HttpRequest
*/
public class OrgREST {// inherited sharing
/*
*get resource
*/
public static String retriveResult(String strResourceName, String strMethod, String strBody) {
String response;
String strEndPonitURL = URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v46.0/' + strResourceName;
if(String.isNotBlank(strResourceName)) {
HttpRequest httpRequest = new HttpRequest();
httpRequest.setMethod(strMethod);
httpRequest.setHeader('Authorization', 'OAuth ' + UserInfo.getSessionId());
httpRequest.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
if(String.isNotBlank(strBody)) {
httpRequest.setBody(strBody);
httpRequest.setHeader('Content-Type', 'application/json');
httpRequest.setHeader('Accept', 'application/json');
}
httpRequest.setEndpoint(strEndPonitURL);
try {
Http http = new Http();
HttpResponse httpResponse = http.send(httpRequest);
if (httpResponse.getStatusCode() == 200 ) {
response = httpResponse.getBody();
}
else {
throw new CalloutException(httpResponse.getBody());
}
}
catch(Exception ex) {
throw ex;
}
}
return response;
}
}
使用该class里面的retriveResult方法,你可以使用Get方式来获取你想要的资源,使用POST向服务器发送消息
2、Send CustomNotificationRESTAPI Use Last Code
public class CustomNotificationRESTAPI {//inherited sharing
public static void (String strNotifiTypeDevName, list<sObject> lstObjects, list<Id> lstRecipients) {
//List<sObject> lstObjects = [select Id from User where Id IN:lstObjectsId];
System.debug('lstObjects' + lstObjects);
String strResponse = null;
System.debug(strNotifiTypeDevName + ':' + strNotifiTypeDevName + ':' + lstRecipients);
if(String.isNotBlank(strNotifiTypeDevName)) {
// Tooling API query
String strResourceQuery = 'tooling/query/?q=select+id,customNotifTypeName+from+CustomNotificationType+where+DeveloperName=\''+ strNotifiTypeDevName +'\'';
// OrgREST Custom Class returns the response as string
strResponse = OrgREST.retriveResult(strResourceQuery, 'GET', null);
System.debug('strResponse:' + strResponse);
//get CustomNotificationType
}
map<String, Object> objData;
if(String.isNotBlank(strResponse)) {
// Deserializeing the response body
map<String, Object> mapJsonData = (map<String, Object>)JSON.deserializeUntyped(strResponse);
// Getting records
list<Object> lstRecordsData = (list<Object>)mapJsonData.get('records');
if(!lstRecordsData.isEmpty()) {
// Converting each object to readable map to get the data
objData = (map<String, Object>)lstRecordsData[0];
}
System.debug('Id ====> '+(String)objData.get('Id'));
}
/*
* Generating JSON body.
* Below code work for bulk record process.
* Recipients are User, Owner, Group or Queue Ids
*/
if(!lstObjects.isEmpty() && !lstRecipients.isEmpty()) {
JSONGenerator jsGen = JSON.createGenerator(true);
jsGen.writeStartObject();
jsGen.writeFieldName('inputs');
jsGen.writeStartArray();
for(sObject obj : lstObjects) {
jsGen.writeStartObject();
// Custom Notification type id
jsGen.writeStringField('customNotifTypeId', (String)objData.get('Id'));
jsGen.writeFieldName('recipientIds');
jsGen.writeStartArray();
// adding mulitiple recipients if any
for(Id idRecipient : lstRecipients) {
jsGen.writeId(idRecipient);
}
jsGen.writeEndArray();
// Notification titile
jsGen.writeStringField('title','Time Hour Contains Taboo');
// Notification body
jsGen.writeStringField('body', 'Your Time Hour Contains Taboo!');
jsGen.writeStringField('targetId', (String)obj.get('Id'));
jsGen.writeEndObject();
}
jsGen.writeEndArray();
jsGen.writeEndObject();
// Converting JSON as String
String strJson = jsGen.getAsString();
System.debug('strJson ====> '+strJson);
// POST URL to send custom notification
String strPOSTURL = 'actions/standard/customNotificationAction';
// Sending post request to send custom notification
String strPostResponse = OrgREST.retriveResult(strPOSTURL, 'POST', strJson);
}
}
}
这里相当于就是先通过GET方式去获取你要的那一个消息提醒(参数strNotifiTypeDevName就是你自定义custom Notification的label name),然后封装你的POST数据,最后还是调用上一个Class中的方法去发送数据到你的salesfroce服务器
注意事项
1、Tigger不能直接调用REST API
前言也说了,发送消息提醒的话一般是处于某种条件下,所以Process Builder和Trigger就经常会遇到类似的问题。但是如果你直接在你的Trigger里面调用REST API的话你会遇到:System.CalloutException: Callout from triggers are currently not supported
意思就是现在还不支持在Trigger里面直接调用REST API!!
So,怎么办!答案就是你必须将调用REST API的操作放到另一个事务中
trigger TimeHourNotificationTrigger on TimeHour__c (after insert) {
for(TimeHour__c selfTimeHour : Trigger.New){
String timeBrief = selfTimeHour.Brief__c;
//List<Id> lstObjectsId = new List<Id>();
//lstObjectsId.add(selfTimeHour.User__c);
List<sObject> lstObjects = new List<sObject>();
lstObjects.add(selfTimeHour);
if(timeBrief.containsIgnoreCase('bug') == true || timeBrief.containsIgnoreCase('bugs') == true || timeBrief.containsIgnoreCase('internal') == true){
System.debug('begin');
//solution:1 CustomNotificationCallout.sendCustomNotification('Time_Hour_Notification', lstObjectsId, new list<Id>{UserInfo.getUserId()});
//solution:1 System.enqueueJob(new CustomNotificationCallout('Time_Hour_Notification', lstObjects, new list<Id>{UserInfo.getUserId()}));
System.debug('end');
}
}
solution 1 :在Future里面调用REST API
但是Future有个很不好的地方就是参数只能是原始类型的不能接受对象,所以你只能传ID然后再查询一边,个人推荐实现Queueable Job
solution 2 : 实现Queueable Job
下面的代码是使用Queueable来做的,另一种方法被注释调,如有需要就请自己动手改一改哈。当然别忘了如果用future的话CustomNotificationRESTAPI.sendCustomNotification那个方法的参数和里面还有以及查询也要改哟。
public with sharing class CustomNotificationCallout implements Queueable,Database.AllowsCallouts {//
public String strNotifiTypeDevName;
//public list<Id> lstObjectsId;
List<sObject> lstObjects = new List<sObject>();
public list<Id> lstRecipients;
public CustomNotificationCallout(String strNotifiTypeDevName, List<sObject> lstObjects, list<Id> lstRecipients){
this.strNotifiTypeDevName = strNotifiTypeDevName;
//this.lstObjectsId = lstObjectsId;
this.lstObjects = lstObjects;
this.lstRecipients = lstRecipients;
System.debug('constror');
}
public void execute(QueueableContext context) {
// Awesome processing logic here
// Chain this job to next job by submitting the next job
CustomNotificationRESTAPI.sendCustomNotification(strNotifiTypeDevName, lstObjects, lstRecipients);
}
/*
@future(callout=true)
public static void sendCustomNotification(String strNotifiTypeDevName, list<Id> lstObjectsId, list<Id> lstRecipients){
System.debug('future');
CustomNotificationRESTAPI.sendCustomNotification(strNotifiTypeDevName, lstObjectsId, lstRecipients);
System.debug(' end future');
} */
}
2、使用Queueable必须实现(implement Database.AllowsCallouts)
如果你的classpublic with sharing class CustomNotificationCallout implements Queueable,Database.AllowsCallouts
只实现了Queueable的话是代码、运行都不会报错,但是是无法发送消息通知的,就像它本身就代表着是否允许Callouts.
PS :如有叙述不清或者错误的地方,恳请指正,留言交流,谢谢!
附上外文网站:https://www.salesforcecodecrack.com/2019/06/send-custom-notifications-using-rest-api.html