您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)怎么在spring boot中實(shí)現(xiàn)消息推送系統(tǒng)設(shè)計(jì),文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
推送系統(tǒng)作為通用的組件,存在的價(jià)值主要有以下幾點(diǎn)
會(huì)被多個(gè)業(yè)務(wù)項(xiàng)目使用,推送系統(tǒng)獨(dú)立維護(hù)可降低維護(hù)成本
推送系統(tǒng)一般都是調(diào)用三方api進(jìn)行推送,三方api一般會(huì)有調(diào)用頻率/次數(shù)限制,被推送的消息需要走隊(duì)列來合理調(diào)用三方api,控制調(diào)用的頻率和次數(shù)
業(yè)務(wù)無關(guān),一般推送系統(tǒng)設(shè)計(jì)成不需要關(guān)心業(yè)務(wù)邏輯
核心技術(shù)
消息隊(duì)列
三方服務(wù)api調(diào)用
安卓app推送
蘋果app推送
微信小程序推送
郵件推送
釘釘推送
短信推送
消息隊(duì)列選用阿里云提供的rocketmq,官方文檔:https://help.aliyun.com/document_detail/55385.html
推送時(shí)序圖
右鍵新窗口打開可以查看高清大圖
可以看到消息推送系統(tǒng)接入的第三方服務(wù)比較多,三方推送的質(zhì)量很難統(tǒng)一,就需要考慮消息的推送的重試了
思路流程
為了控制并發(fā),所有的推送都先發(fā)到rocketmq隊(duì)列里,每次推送的個(gè)數(shù)通過控制隊(duì)列的消費(fèi)的客戶端的數(shù)量來實(shí)現(xiàn)
安卓和蘋果都可以使用信鴿的推送服務(wù)
信鴿推送需要客戶端進(jìn)行集成,客戶端sdk參考: https://xg.qq.com/xg/ctr_index/download
目前信鴿個(gè)人開發(fā)者仍然是可以申請(qǐng)的,賬號(hào)建立后,創(chuàng)建andorid和ios項(xiàng)目
記錄下這里的 APP ID和SECRET KEY,服務(wù)端進(jìn)行推送時(shí)需要這兩個(gè)參數(shù)
推送異常處理,推送異常時(shí),需要重試,重試可以利用消息隊(duì)列本身的重試機(jī)制,也可以自行實(shí)現(xiàn)重試邏輯
安卓app推送
官方文檔: https://xg.qq.com/docs/android_access/jcenter.html
代碼庫: https://github.com/xingePush/xinge-api-java
<!-- 信鴿推送客戶端 --> <dependency> <groupId>com.github.xingePush</groupId> <artifactId>xinge</artifactId> <version>1.2.1</version> </dependency>
核心代碼如下
Map<String, Object> messagePayload = new HashMap<String, Object>(1); messagePayload.put("user_id", 1); messagePayload.put("msg_title", "消息標(biāo)題"); messagePayload.put("msg_content", "消息內(nèi)容"); messagePayload.put("msg_type", 1); messagePayload.put("data", Lists.newHashMap("order_id", 1)); XingeApp xinge = new XingeApp(androidAccessId, androidSecretKey); MessageAndroid message = new MessageAndroid(); ClickAction action = new ClickAction(); action.setActionType(ClickAction.TYPE_ACTIVITY); message.setAction(action); message.setContent(JsonUtil.toJsonString(messagePayload)); message.setType(MessageAndroid.TYPE_MESSAGE); message.setExpireTime(86400); message.setCustom(new HashMap<String, Object>(1)); JSONObject response = xinge.pushSingleDevice("用戶的PushToken", message); if (response.getInt(RET_CODE) != 0) { // 推送異常了,進(jìn)行日志記錄等 }
蘋果app推送
使用pushy庫進(jìn)行推送
<!-- IOS推送客戶端 --> <dependency> <groupId>com.turo</groupId> <artifactId>pushy</artifactId> <version>0.13.3</version> </dependency>
Map<String, Object> aps = new HashMap<String, Object>(1); aps.put("alert", "推送內(nèi)容"); aps.put("sound", "default"); aps.put("badge", 1); Map<String, Object> data = new HashMap<String, Object>(1); data.put("msgTitle", "推送標(biāo)題"); data.put("msgContent", "推送內(nèi)容"); data.put("msgType", "1"); data.put("userId", "13288888888"); data.put("data", Lists.newHashMap("order_id", 1)); Map<String, Object> messagePayload = new HashMap<String, Object>(1); messagePayload.put("aps", aps); messagePayload.put("data", data); ApnsClient apnsClient = new ApnsClientBuilder() .setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST) .setClientCredentials(this.getClass().getClassLoader().getResourceAsStream("推送證書相對(duì)resources目錄的路徑"), "") .build(); String payload = JsonUtil.toJsonString(messagePayload); String token = TokenUtil.sanitizeTokenString("app用戶的pushToken"); SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(token, "com.suxiaolin.app1", payload); PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>> sendNotificationFuture = apnsClient.sendNotification(pushNotification); final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse = sendNotificationFuture.get(); if (pushNotificationResponse.isAccepted()) { System.out.println("Push notification accepted by APNs gateway."); } else { System.out.println("Notification rejected by the APNs gateway: " + pushNotificationResponse.getRejectionReason()); if (pushNotificationResponse.getTokenInvalidationTimestamp() != null) { System.out.println("\t…and the token is invalid as of " + pushNotificationResponse.getTokenInvalidationTimestamp()); } }
使用信鴿庫進(jìn)行推送
當(dāng)然也可以使用信鴿提供的ios推送,邏輯和安卓app的推送差不多
ios的信鴿客戶端可以和android的客戶端共用,不需要引入新的jar包了
JSONObject messagePayload = new JSONObject(); Map<String, Object> custom = new HashMap<String, Object>(); messagePayload.put("title", "推送標(biāo)題"); messagePayload.put("body", "推送內(nèi)容"); messagePayload.put("user_id", 1); messagePayload.put("msg_type", 1); messagePayload.put("data", Lists.newArrayList("orderId", 1)); XingeApp xinge = new XingeApp(iosAccessId, iosSecretKey); MessageIOS message = new MessageIOS(); message.setType(MessageIOS.TYPE_APNS_NOTIFICATION); message.setExpireTime(86400); message.setAlert(content); message.setBadge(1); message.setCategory("INVITE_CATEGORY"); message.setCustom(messagePayload); response = xinge.pushSingleDevice("app用戶的pushToken", message, XingeApp.IOSENV_PROD); if (response.getInt(RET_CODE) != 0) { // 推送異常了 }
釘釘推送
public static boolean send(String content, String title, Set<String> receivers) { try { HttpUtil.ResponseWrap result = HttpUtil.postWrap(ddUrl, "{\n" + " \"msgtype\": \"text\",\n" + " \"text\": {\"content\":\"" + title + "\r\n" + content + "\n|" + receivers.stream().map(r -> "@" + r).collect(Collectors.joining(" ")) + "\"},\n" + " \"at\": {\n" + " \"atMobiles\": [" + receivers.stream().map(r -> "\"" + r + "\"").collect(Collectors.joining(",")) + "], \n" + " \"isAtAll\": false\n" + " }\n" + " }"); return result.getStatusCode() == 200; } catch (Exception e) { return false; } }
完整代碼參考DingTalkUtil.java
使用http請(qǐng)求就可以請(qǐng)求了
郵件推送
發(fā)送郵件可以使用java的javax.mail庫,smtp協(xié)議發(fā)送郵件
<dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.7</version> </dependency>
示例代碼參考: EmailSender.java
短信推送
短信服務(wù)商眾多,郵件一般有統(tǒng)一的smtp協(xié)議可以使用,短信沒有協(xié)議,但是一般使用http發(fā)送短信 比如以下的短信服務(wù)商
253云通訊:zz.253.com/api_doc/kai…
短信服務(wù)- 又拍云: https://www.upyun.com/products/sms
消息&短信_(tái)MSGSMS_云通信_(tái)短信- 華為云: https://www.huaweicloud.com/product/msgsms.html
消息隊(duì)列的特性
消息隊(duì)列消費(fèi)異常后會(huì)自動(dòng)進(jìn)行重試
一些注意的點(diǎn)
微信小程序每次支付可以生成一個(gè)推送碼,需要保存到數(shù)據(jù)庫或者緩存里,并且每個(gè)碼只能推送3條消息
因?yàn)橄㈥?duì)列的消費(fèi)在消息量大的時(shí)候具有一定的延時(shí),這就為取消消息推送提供了可能,可以為每條消息生成一個(gè)唯一的uuid,取消的時(shí)候把這個(gè)uuid設(shè)計(jì)進(jìn)redis里,推送時(shí)檢查這個(gè)uuid是否在redis里決定推送與否
雖然推送存在不可控制的異常,比如三方推送服務(wù)出現(xiàn)了異常,但是也存在調(diào)用方傳遞參數(shù)異常,可以推送接口調(diào)用的返回值判斷是否調(diào)用推送系統(tǒng)成功,也可以記錄到日志里,這樣在調(diào)查異常原因時(shí)就比較容易
上述就是小編為大家分享的怎么在spring boot中實(shí)現(xiàn)消息推送系統(tǒng)設(shè)計(jì)了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。