rabbitMq實現系統內的簡訊傳送設計&動態獲取BEAN

oktokeep發表於2024-06-06

rabbitMq實現系統內的簡訊傳送設計&動態獲取BEAN

1.簡訊非系統的重要節點操作,可以在任務完成之後,比如下單成功,傳送下單成功的mq訊息,簡訊服務接收到mq訊息,
動態的判斷該簡訊的code,透過全域性公共的父類(呼叫中臺等介面獲取全部所有需要的物件引數),獲取簡訊中的{mobile}等引數來替換簡訊模板中的可變數。
這樣系統中的所有的傳送簡訊,都可以繼承該父類,獲取引數,從而實現方便快捷的擴充套件簡訊接入和對原來的簡訊模板內容的修改或新增簡訊中的可變數。

2.簡訊服務封裝好簡訊的code和簡訊中的需要的引數,然後解析出來文字,將mobile和content等重要引數,呼叫第三方的簡訊供應商介面來傳送簡訊。

3.系統中的簡訊模板表設計如下:

CREATE TABLE `tbl_sms_template` (
  `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `text_code` VARCHAR(80) NOT NULL COMMENT '唯一標識',
  `content` VARCHAR(1000) NOT NULL COMMENT '簡訊訊息內容,動態引數以{開頭,}結尾',
  `send_source_srv` VARCHAR(30) DEFAULT NULL COMMENT '傳送方服務來源',
  `send_source_biz` VARCHAR(30) DEFAULT NULL COMMENT '傳送方業務來源',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
  `create_op` VARCHAR(50) DEFAULT NULL COMMENT '建立人',
  `update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  `is_delete` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '刪除標記 0未刪除 1已刪除',
  PRIMARY KEY (`id`),
  UNIQUE KEY `text_code` (`text_code`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='簡訊模板表'


CREATE TABLE `tbl_sms_log` (
  `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'ID主鍵',
  `mobile` BIGINT(20) DEFAULT NULL COMMENT '手機號',
  `content` TEXT COMMENT '簡訊內容',
  `type` INT(1) DEFAULT NULL COMMENT '分類',
  `remark` VARCHAR(100) DEFAULT NULL COMMENT '備註',
  `req_ip` VARCHAR(60) DEFAULT NULL COMMENT '請求IP',
  `req_beg_time` TIMESTAMP NULL DEFAULT NULL COMMENT '請求時間',
  `req_beg_back_time` TIMESTAMP NULL DEFAULT NULL COMMENT '請求返回時間',
  `req_status` INT(1) DEFAULT NULL COMMENT '傳送結果(1:成功2:失敗)',
  `res` VARCHAR(150) DEFAULT NULL COMMENT '簡訊返回結果',
  `supplier` INT(1) DEFAULT '1' COMMENT '簡訊平臺服務供應商',
  `send_source_srv` VARCHAR(30) DEFAULT NULL COMMENT '傳送方服務來源',
  `send_source_biz` VARCHAR(30) DEFAULT NULL COMMENT '傳送方業務來源',
  `account_type` INT(1) DEFAULT NULL COMMENT '簡訊賬戶通道型別',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
  `create_op` VARCHAR(50) DEFAULT NULL COMMENT '建立人',
  `update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  `is_delete` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '刪除標記 0未刪除 1已刪除',
  PRIMARY KEY (`id`),
  KEY `create_time` (`create_time`),
  KEY `mobile` (`mobile`,`req_status`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='簡訊傳送日誌表'

4.測試簡訊的方法:
4.1.走全流程等透過系統節點來觸發,看是否符合預期結果。
4.2.可以透過rabbitMq管理後臺,找到佇列名稱,直接將json字串透過佇列來傳送,檢查簡訊服務是否正常接收且簡訊是否正常傳送。

4.3.可以透過rabbitMq管理後臺,找到交換機exchange名稱,直接將json字串透過交換機exchange和路由key來傳送,檢查簡訊服務是否正常接收且簡訊是否正常傳送。

5.具體實現,虛擬碼
傳送端

//取消訂單
    CANCEL_ORDER_EVENT("sys-order-action","action.cancel.order.key","取消訂單事件"),

   //傳送MQ  只需要一個訂單號。orderNo可以封裝到一個物件中。
   //傳送端不關心具體的簡訊可變數引數,減少耦合程式碼。
    baseProducer.sendTopicMessage(CANCEL_ORDER_EVENT.exchange, CANCEL_ORDER_EVENT.routingKey, orderNo);

接收端實現類

配置路由key和實現類的列舉類
CANCEL_ORDER_EVENT("action.cancel.order.key", "CancelOrderService"), //距離還車時間事件
    
配置簡訊模板:    
    //傳送簡訊給售貨商
    CANCEL_ORDER_TO_OWNER("CancelOrderToOwner", "您的訂單(訂單號:$orderNo$),訂單金額($orderAmt$),請在($orderAddress$)配送地址,已取消,快去APP看看吧!")
    //傳送簡訊給買貨方
    CANCEL_ORDER_TO_BUYER("CancelOrderToBuyer", "您的訂單(訂單號:$orderNo$),訂單金額($orderAmt$),請在($orderAddress$)配送地址,已取消,快去APP看看吧!")


@RabbitListener(bindings = {@QueueBinding(value = @Queue(value = "order_sms_queuetest", durable = "true"),
            exchange = @Exchange(value = "sys-order-action", durable = "true", type = "topic"), key = "action.#")
}, containerFactory = "orderRabbitListenerContainerFactory")
public void process(Message message) {
    log.info("receive order action message: " + new String(message.getBody()));
    try {
        //構建簡訊傳送物件
        SmsMessage smsMessage = createSmsMessageService(message);
        if (Objects.nonNull(smsMessage)) {
            //傳送簡訊
            sendSMSMessageData(smsMessage);
        }
    } catch (Exception e) {
        log.info("訂單簡訊傳送異常,msg:[{}]", e);
    }


public SmsMessage createSmsMessageService(Message message){
        //1.獲取路由key
        String routeKeyName = message.getMessageProperties().getReceivedRoutingKey();
        
        //2.根據路由key 找到 實現類的service名稱 (配置路由key和實現類的列舉類)
        String serviceName = getSmsServiceTemplate(routeKeyName);
        if(StringUtils.isBlank(serviceName))
        {
            log.info("該事件沒有需要傳送得簡訊,routeKeyName:[{}]",routeKeyName);
            return null;
        }
        
        //3.首字母小寫
        serviceName = serviceName.substring(0, 1).toLowerCase() + serviceName.substring(1);
        log.info("該事件獲取的smsMessage service為:[{}]",serviceName);
        
        //4.父類  根據getBean方式獲取實現子類
        
        //5.呼叫實現子類獲取簡訊傳送的物件(簡訊引數)
        return smsMessage;
    }

//動態獲取BEAN 參考:
Java動態獲取實現類 Class.forName(clazz).newInstance()和applicationContext.getBean, bean Map尋找方式,Java Map定義和初始化方法
https://www.cnblogs.com/oktokeep/p/18235912

@Service
public class OrderSmsService implements  ApplicationContextAware {

    private ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    
    public <T> T getBean(String beanName) {
        if (applicationContext.containsBean(beanName)) {
            return (T) applicationContext.getBean(beanName);
        } else {
            return null;
        }
    }
    
}

擴充套件:
基礎底層簡訊服務的設計思路
https://www.cnblogs.com/oktokeep/p/17663970.html

相關文章