基於Redis 實現的消息發佈與訂閱

基於redis 的實現的 消息中間件代碼:

小弟最近在維護一個 代碼內異常發送dingding消息的功能。覺得redis消息中間件還是挺好用的。於是趕緊記下來;

redis發佈消息時基於通道的概念。所以 先定義好一個通道,比如有個枚舉

public enum RedisMsgEnum {
    SEND_MSG_CHNNEL("CHANNEL_CASE_MSG", "REDIS CHANNEL專用");

    private String channel;

    private String name;

    RedisMsgEnum(String channel, String name) {
        this.channel = channel;
        this.name = name;
    }

    public String getChannel() {
        return channel;
    }

    public void setChannel(String channel) {
        this.channel = channel;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

 由於是基於boot 2.1.X 項目,所以要先初始化 redis消息監聽器

@Configuration
public class RedisSubListenerConfig {
    //初始化監聽器
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                            MessageListenerAdapter listenerAdapter) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.addMessageListener(listenerAdapter, new PatternTopic(RedisMsgEnum.SEND_MSG_CHNNEL.getChannel()));
        return container;
    }
    //利用反射來創建監聽到消息之後的執行方法
    @Bean
    MessageListenerAdapter listenerAdapter(RedisConsumer redisReceiver) {
        return new MessageListenerAdapter(redisReceiver, "receiveMessage");
    }
   //使用默認的工廠初始化redis操作模板
    @Bean
    StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
        return new StringRedisTemplate(connectionFactory);
    }
}

這樣redis 就完成了基本配置,現在寫類似MQ 的 生產者和消費者:

生產者:

@Service
public class RedisSender {
    private static final Logger logger = LoggerFactory.getLogger(RedisSender.class);

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    //向通道發送消息的方法
    public void sendChannelMess(String channel, String message) {
        stringRedisTemplate.convertAndSend(channel, message);
    }
}

消費者:

@Service
public class RedisConsumer {

    private static final Logger logger = LoggerFactory.getLogger(RedisConsumer.class);

    private static final String PROD_ENVIRONMENT = "prod";

    private static final String HUIDU_ENVIRONMENT = "huidu";

    public void receiveMessage(String message) {
        //收到通道的消息之後執行業務
        DingDingMsgSendUtils.sendDingDingGroupMsg(
                DingTokenEnum.SEND_SMS_BY_DEVELOPER_TOKEN.getToken(),
                "【kashtrees-app-進件超時-"+ SpringContextUtil.getActiveProfile()+"-環境】異常,用戶id:"+message,
                DingMsgPhoneEnum.DEVELOPER_PHONE_yansf.getPhone());
    }
}

發送入口:

private static int corePoolSize = Runtime.getRuntime().availableProcessors();
//調整隊列數 拒絕服務
private static ThreadPoolExecutor executor  = new ThreadPoolExecutor(corePoolSize, corePoolSize+1, 10l, TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(10000));

private void sendChannelMess(RiskUserInfoParamVo riskUserInfoParamVo) {
        Runnable task = new Runnable() {
            @Override
            public void run() {
                //思考如何返回給用戶信息ws
                redisSender.sendChannelMess(RedisMsgEnum.SEND_MSG_CHNNEL.getChannel(),// 通道
                                riskUserInfoParamVo.getUserId()+"");
            }
        };
        executor.execute(task);
}

釘釘發送工具類:

public class DingDingMsgSendUtils {

    private static final Logger logger = LoggerFactory.getLogger(DingDingMsgSendUtils.class);


    /**
     * 處理髮送的釘釘消息
     *
     * @param accessToken
     * @param textMsg
     */
    private static void dealDingDingMsgSendTest(String accessToken, String textMsg) {
        HttpClient httpclient = HttpClients.createDefault();
        String WEBHOOK_TOKEN = "https://oapi.dingtalk.com/robot/send?access_token=" + accessToken;
        HttpPost httppost = new HttpPost(WEBHOOK_TOKEN);
        httppost.addHeader("Content-Type", "application/json; charset=utf-8");

        StringEntity se = new StringEntity(textMsg, "utf-8");
        httppost.setEntity(se);

        try {
            org.apache.http.HttpResponse response = httpclient.execute(httppost);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String result = EntityUtils.toString(
                        response.getEntity(), "utf-8");
                System.out.println("【發送釘釘羣消息】消息響應結果:"
                        + JSON.toJSONString(result));
            }
        } catch (Exception e) {
            System.out.println("【發送釘釘羣消息】error:" + e.getMessage()+e);
        }
    }

    /**
     * 發送釘釘羣消息
     *
     * @param accessToken
     * @param content
     */
    public static void sendDingDingGroupMsgTest(String accessToken, String content) {
        String textMsg = "{ \"msgtype\": \"text\", \"text\": {\"content\": \"" + content + "\"}}";
        dealDingDingMsgSend(accessToken, textMsg);
    }

    /**
     * 發送釘釘羣消息(可以艾特人)
     *
     * @param accessToken 羣機器人accessToken
     * @param content     發送內容
     * @param atPhone     艾特人電話,如:176********,156********,
     */
    public static void sendDingDingGroupMsgTest(String accessToken, String content, String atPhone) {
        content = content.replace("\"", "'");
        String textMsg = "";

//        String textMsg = "{\n" +
//                "    \"msgtype\": \"text\", \n" +
//                "    \"text\": {\n" +
//                "        \"content\": \"" + content + "\"\n" +
//                "    }, \n" +
//                "    \"at\": {\n" +
//                "        \"atMobiles\": [\n" +
//                "            " + atPhone +
//                "        ], \n" +
//                "        \"isAtAll\": false\n" +
//                "    }\n" +
//                "}";

        MsgDto msgDto = new MsgDto();
        msgDto.setMsgtype("text");

        TextDto textDto = new TextDto();
        textDto.setContent(content);
        msgDto.setText(textDto);

        AtDto atDto = new AtDto();
        atDto.setIsAtAll(false);

        List<String> result = Arrays.asList(atPhone.split(","));
        atDto.setAtMobiles(result);
        msgDto.setAt(atDto);

        textMsg = JSONSerializer.toJSON(msgDto).toString();
        System.out.println(textMsg);
        dealDingDingMsgSend(accessToken, textMsg);
    }

    //@Value("${spring.profiles.active}")
    //private String profile;

    public static void main(String[] args) {
        try {
            int s = Integer.parseInt("df12");
//            System.out.println(1 / 0);
        } catch (Exception e) {
            e.printStackTrace();
            //System.out.println("11"+e.getStackTrace().);
            StringBuffer sb=new StringBuffer();
            for(StackTraceElement elem : e.getStackTrace()) {
                 sb.append(elem+">>>>>>>>>>>>>>>>>>>>");
            }
            System.out.println(sb.toString());
            sendDingDingGroupMsg(
                    DingTokenEnum.SEND_SMS_BY_DEVELOPER_TOKEN.getToken(),
                    "【JAVA系統消息】釘釘消息推送測試,by:..."
                            //+e.printStackTrace();
                    //+ e.getMessage(),
                    +"環境,異常:"+sb.toString(),
                    DingMsgPhoneEnum.DEVELOPER_PHONE_yansf.getPhone());
        }

        //異常捕獲
        /*try{
            //todo
        } catch (Exception ex) {
            DingDingMsgSendUtils.sendDingDingGroupMsg(DingTokenEnum
                    .SEND_SMS_BY_DEVELOPER_TOKEN.getToken()
                    , "***異常,"
                    //+ profile
                    + "環境,errorMsg=" + ex,
                    DingMsgPhoneEnum.DEVELOPER_PHONE_yansf.getPhone());
        }*/

    }


    /**
     * 發送釘釘羣消息(可以艾特人)
     *
     * @param accessToken 羣機器人accessToken
     * @param content     發送內容
     * @param atPhone     艾特人電話,如:176********,156********,
     */
    public static void sendDingDingGroupMsg(String accessToken, String content, String atPhone) {
        content = content.replace("\"", "'");
        String textMsg = "";

        MsgDto msgDto = new MsgDto();
        msgDto.setMsgtype("text");

        TextDto textDto = new TextDto();
        textDto.setContent(content);
        msgDto.setText(textDto);

        AtDto atDto = new AtDto();
        atDto.setIsAtAll(false);

        List<String> result = Arrays.asList(atPhone.split(","));
        atDto.setAtMobiles(result);
        msgDto.setAt(atDto);

        textMsg = JSONSerializer.toJSON(msgDto).toString();
        logger.error("textMsg:",textMsg);
        dealDingDingMsgSend(accessToken, textMsg);
    }

    /**
     * 處理髮送的釘釘消息
     *
     * @param accessToken
     * @param textMsg
     */
    private static void dealDingDingMsgSend(String accessToken, String textMsg) {
        HttpClient httpclient = HttpClients.createDefault();
        String WEBHOOK_TOKEN = "https://oapi.dingtalk.com/robot/send?access_token="+accessToken ;
        HttpPost httppost = new HttpPost(WEBHOOK_TOKEN);
        httppost.addHeader("Content-Type", "application/json; charset=utf-8");

        StringEntity se = new StringEntity(textMsg, "utf-8");
        httppost.setEntity(se);

        try {
            org.apache.http.HttpResponse response = httpclient.execute(httppost);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String result = EntityUtils.toString(
                        response.getEntity(), "utf-8");
                logger.error("【發送釘釘羣消息】消息響應結果:"
                        + JSON.toJSONString(result));
            }
        } catch (Exception e) {
            logger.error("【發送釘釘羣消息】error:" + e.getMessage()+e);
        }
    }

}

當然啦。需要先獲取釘釘的token 這個就不提供了。

以上就是完整的  基於redis 訂閱與發佈的 服務簡單實現了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章