之前使用阿里平台的短信和邮件发送服务,现在需要根据发送回执记录用户是否真实收到消息推送。查看文档发现可以通过消息服务MNS来实现,在此记录一下相关经验。
邮件消息回执处理见另一篇文章:https://blog.youkuaiyun.com/new_programmer_h/article/details/115182709
短信消息回执处理:
官方文档地址:https://help.aliyun.com/document_detail/101508.html?spm=a2c4g.11186623.6.641.46e2633edOvlfO
阿里云控制台配置:通用设置中开启状态报告接收,自动创建队列用于接收回执消息,地域选择可以开启内网请求访问,不开启默认走公网请求,请根据自己实例所在进行配置
SDK-DEMO下载地址:https://help.aliyun.com/document_detail/101874.html?spm=5176.10629532.0.dexternal.35cd1cbeHO7VdQ

在编辑代码的时候有个问题需要注意一下:MNS消息接收的sdk中有两个jar包不能直接从maven中引入,需要自己手动处理一下,上传至自己maven仓库或者直接手动引入,具体的jar在demo中的lib中可以找到。需要注意一下,发送短信用的是:dysmsapi,MNS使用的是:dybaseapi。
alicom-mns-receive-sdk-1.0.1.jar
aliyun-java-sdk-dybaseapi-1.0.0.jar
因为只使用了接收消息回执,重写了demo中的DefaultAlicomMessagePuller类,线程池使用默认配置,其他根据自己实际情况配置
public void startSmsReciptListener() throws Exception {
logger.info("<<<<<<<<<<<<<<<<<<<<<<<<<<<<startSmsReciptListener:短信消息回执监听启动>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
SmsMessagePuller puller = new SmsMessagePuller();
puller.setDebugLogOpen(smsOptionsProperties.getDebugLogOpen());//和服务端联调问题时开启,平时无需开启,消耗性能
String accessKeyId = "accessKeyId";//此处需要替换成开发者自己的AK信息
String accessKeySecret="accessKeySecret";//此处需要替换成开发者自己的AK信息
String messageType="messageType";//1:短信回执:SmsReport 2:短息上行:SmsUp 3:语音呼叫:VoiceReport 4:流量直冲:FlowReport
String queueName = "queueName ";//短信平台通用设置中的默认队列名称
String regionIdForPop = "regionIdForPop ";//指定与ECS相同的地域
String endpointNameForPop = "endpointNameForPop ";//指定与ECS相同的地域
String domainForPop = "domainForPop";//指定对应地域的"消息接收1"用的域名
String mnsAccountEndpoint = "mnsAccountEndpoint ";//指定对应地域的"消息接收2"用的域名
puller.startReceiveMsg(accessKeyId,accessKeySecret,messageType,queueName,regionIdForPop,endpointNameForPop,domainForPop,mnsAccountEndpoint,new SmsReceiptListener());
}
因为阿里云一个账户只有一个短信服务平台,消息回执的队列又是默认生成一个对应的默认队列,所以需要自己在接收消息后通过业务层面自行处理进行区分,本人通过发送短信时候的outid字段进行区分,该字段没有实际业务意义,发送到阿里平台后会原样返回,所以我将所在环境通过该字段发送后在接收消息处理时判断是否是当前环境消息。这时候有一点需要注意:处理完消息后,是否将队列中的消息删除是根据处理结果返回的true/false进行判断的,如果返回false,消息会重新进入队列。所以我首先判断是否是当前环境消息,非本环境消息直接返回false,重新进入队列。(这里有一个问题,就是这条消息可能一直没被对应的环境拉取到,只能自行在代码层面进行幂等性处理。需要后期优化)
static class SmsReceiptListener implements SmsMessageListener {
private Gson gson = new Gson();
@Override
public boolean dealSmsMessage(Message message) {
// logger.info("<<<<<<<<<<<<<SmsReceiptListener:短信消息回执messageId:"+message.getMessageId()+",处理开始:"+DateUtil.getCurrDate()+">>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
try{
//自定义实体接收参数
SmsMessageBO smsMessageBO=gson.fromJson(message.getMessageBodyAsString(), SmsMessageBO.class);
//判断是否是当前环境消息
if(CheckUtils.isNotEmpty(smsMessageBO.getOutId()) && smsMessageBO.getOutId().equals(staticActive)){
// logger.info(message.getMessageBodyAsString()+",处理结束:"+DateUtil.getCurrDate());
}else{
// logger.info("<<<<<<<<<<<<<SmsReceiptListener:非当前环境消息回执:" + smsMessageBO.getOutId()+",处理结束:"+DateUtil.getCurrDate()+">>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
return false;
}
}catch(com.google.gson.JsonSyntaxException e){
logger.error("error_json_format:"+message.getMessageBodyAsString(),e);
//理论上不会出现格式错误的情况,所以遇见格式错误的消息,只能先delete,否则重新推送也会一直报错
return true;
} catch (Throwable e) {
logger.error("处理短信消息回执失败:"+message.getMessageBodyAsString(),e);
return false;
}
//消息处理成功,返回true, SDK将调用MNS的delete方法将消息从队列中删除掉
return true;
}
}
到这一步就成功接收到消息回执了,可以进行记录、重发等后续业务处理了。
仅以此记录成长,若是能提供帮助,再好不过了。
829

被折叠的 条评论
为什么被折叠?



