springBoot项目部署rocketmq,使用mq消息对了实现微信公众号客服消息推送

第一步:安装部署rocketMq,这一步网上教程很多,这里就不多说了,直接上代码

第二步:在pom文件中引入rocketMq的jar包

<!--rocketmq-->
<dependency>
	<groupId>org.apache.rocketmq</groupId>
	<artifactId>rocketmq-client</artifactId>
	<version>4.2.0</version>
</dependency>

第三步:为了项目看起来更赶紧整洁一些,可以把一些基本的配置创建一个类

package xxx.xxx.xxx.rocketMQ.config;

/**
 * @Description:rocketMq基本配置
 * @Date: Created in 9:16 2021/3/18
 */
public class MqConfig {
    //mq的默认端口
    public static final String NAME_SERVER = "127.0.0.1:9876";

    // 生产者组名-推送
    public static final String PRODUCER_GROUP_PUSH_MSG = "producer_group_push_msg";
    // 消费者组名-推送
    public static final String CONSUMER_GROUP_PUSH_MSG = "consumer_group_push_msg";

    /*********** 我们的项目商城模块推送使用了mq,拿在这里做例子 *************/
    // topic- 商城(key和value都可以自定义)
    public static final String MALL = "mall";
    // 延时消息:关闭订单tag(topic MALL 的tag)
    public static final String CLOSE_MALL_ORDER = "close_mall_order";
    // 延时消息:自动收货tag(topic MALL 的tag)
    public static final String RECEIPT_MALL_ORDER = "receipt_mall_order";
    // 购物车tag(topic MALL 的tag)
    public static final String DEL_CART = "del_cart";

    // topic- 微信公众号
    public static final String TOPIC_GZH = "topic_gzh";

    // topic- 极光app推送
    public static final String TOPIC_JG_APP = "topic_jg_app";


}

第四步:创建生产者

package xxx.xxx.xxx.rocketMQ.producer;

import xxx.xxx.xxx.rocketMQ.config.MqConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class MqProducer {
    @Bean
    public DefaultMQProducer getRocketMQProducer() {
        DefaultMQProducer producer;
        producer = new DefaultMQProducer(MqConfig.PRODUCER_GROUP_PUSH_MSG);
        producer.setNamesrvAddr(MqConfig.NAME_SERVER);
        //Rocket默认开启了VIP通道,VIP通道端口为10911-2=10909。若Rocket服务器未启动端口10909,则报connect to <> failed,所以要关闭一下
        producer.setVipChannelEnabled(false);
        try {
            producer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
        return producer;
    }

}

第五步:创建消费者

package xxx.xxx.xxx.rocketMQ.consumer;

import xxx.xxx.xxx.rocketMQ.config.MqConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

/**
 * @Description: 消费者
 * @Date: Created in 9:18 2021/3/18
 */
@Slf4j
@Configuration
public class RocketMQConsumer {
    //消费者需要引入监听
    @Resource
    private RocketMsgListener msgListener;
    @Bean
    public DefaultMQPushConsumer getRocketMQConsumer(){
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(MqConfig.CONSUMER_GROUP_PUSH_MSG);
        consumer.setNamesrvAddr(MqConfig.NAME_SERVER);
        //将监听引入消费者
        consumer.registerMessageListener(msgListener);
        //Rocket默认开启了VIP通道,VIP通道端口为10911-2=10909。若Rocket服务器未启动端口10909,则报connect to <> failed,关闭默认开启的vip通道
        consumer.setVipChannelEnabled(false);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        try {
            //将要使用的TOPIC引入(可订阅多个tag,但是一个消息只能有一个tag)
            //另一种写法:consumer.subscribe("TopicA", "tagA||tagB"); ‘*’代表MALL的所有tag                            
            consumer.subscribe(MqConfig.MALL, "*"); 
            consumer.subscribe(MqConfig.TOPIC_GZH, "*");
            consumer.start();
        }catch (MQClientException e){
            e.printStackTrace();
        }
        return consumer;
    }
}

第六步:创建消费者调用的监听 (方法中有微信公众号消息推送和商城模块的个别操作,仅供参考)

package xxx.xxx.xxx.rocketMQ.consumer;

import xxx.xxx.xxx.pay.utils.WxUtil;
import xxx.xxx.xxx.rocketMQ.config.MqConfig;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 消息消费监听
 */
@Component
@Slf4j
public class RocketMsgListener implements MessageListenerConcurrently {
    //微信的工具类
    @Autowired
    private WxUtil wxUtil;

    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext context) {
        if (CollectionUtils.isEmpty(list)) {
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
        for (MessageExt messageExt : list) {
            log.info("接受到的消息为:" + new String(messageExt.getBody()));
            int reConsume = messageExt.getReconsumeTimes();
            // 消息已经重试了3次,如果不需要再次消费,则返回成功
            if (reConsume == 3) {
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
            //查看消费的是否为微信公众号的Topic
            if (messageExt.getTopic().equals(MqConfig.TOPIC_GZH)) {
                String tags = messageExt.getTags();
                switch (tags) {
                    case "push_gzh_template":
                        log.info("公众号推送 tag == >>" + tags);
                        JSONObject msgBody = JSONObject.fromObject(new String(messageExt.getBody()));
                        //targetOpenidStr or targetMemberType or orderType 为使用mq消息队列请求时自定义的
                        String targetOpenidStr = msgBody.getString("targetOpenidStr");
                        int targetMemberType = msgBody.getInt("targetMemberType");
                        int orderType = msgBody.getInt("orderType");
                        //Message()方法中的keys值
                        String orderId = messageExt.getKeys();
                        // 获取具体推送内容(根据自己的逻辑去获取值)
                        String resContent = "";
                        if (StringUtils.isNotBlank(targetOpenidStr)) {
                            //获取微信的token
                            String wxAccessToken = wxUtil.getAccess_token("微信的appId", "微信的ApiKey");
                            if (StringUtils.isBlank(wxAccessToken)) {
                                log.error("公众号推送客服消息失败: 未获取到wxAccessToken");
                                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                            }
                            String[] openidArr = targetOpenidStr.split(",");
                            for (int i = 0; i < openidArr.length; i++) {
                                String s = openidArr[i];
                                JSONObject jsonObject = new JSONObject();
                                jsonObject.put("content", resContent);
                                //调用微信 推送客服消息
                                wxUtil.sxyPushCustomerMsg(s, wxAccessToken, jsonObject);
                            }
                        }
                        break;
                    default:
                        log.info("未匹配到Tag == >>" + tags);
                        break;
                }
            } else if (messageExt.getTopic().equals(MqConfig.MALL)) {//商城Topic
                String tags = messageExt.getTags();
                switch (tags) {
                    case MqConfig.CLOSE_MALL_ORDER: //关闭订单tag
                        // 要处理的订单 orderId为调用mq队列时将订单id录入body字段
                        String orderId = new String(messageExt.getBody());
                        // todo 自己的业务流程
                        xxxService.xxxxx(orderId);
                        break;
                    case MqConfig.RECEIPT_MALL_ORDER: //自动收货tag
                        // 要自动收货订单
                        String orderId2 = new String(messageExt.getBody());
                        xxxService.xxxxx(orderId);
                        break;
                    default:
                        log.info("未匹配到Tag == >>" + tags);
                        break;
                }
            }
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
}

第七步:微信的工具类WxUtil(用于例子中的微信公众号推送,不需要可以忽略)

package xxx.xxx.xxx.pay.utils;

import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @Date: Created in 10:29 2019/8/9
 */
@Slf4j
@Component
public class WxUtil {
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * @Description: 获取access_token
     * @date: 2019/7/12 11:14
     * @param: [appid, appsecret]
     * @return: java.lang.String
     */
    public String getAccess_token(String appid, String appsecret) {
        // 先判断redis中是否存在
        String token = redisTemplate.opsForValue().get("自定义存入redis中的key");
        if (StringUtils.isBlank(token) == false) {
            // token还未过期,获取后直接返回,无需重新获取
            log.info("======从Redis中获取的微信公众平台access_token:" + token);
            return token;
        }
        // token已过期或不存在,需重新获取
        redisTemplate.delete("自定义存入redis中的key");
        String access_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + "&appid=" + appid + "&secret=" + appsecret;
        String message = "";
        try {
            URL url = new URL(access_url);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.connect();
            //获取返回的字符
            InputStream inputStream = connection.getInputStream();
            int size = inputStream.available();
            byte[] bs = new byte[size];
            inputStream.read(bs);
            message = new String(bs, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //获取access_token
        JSONObject jsonObject = JSONObject.fromObject(message);
        log.info("======从微信api获取的微信公众平台access_token:" + jsonObject.toString());
        String accessToken = jsonObject.getString("access_token");
        String expires_in = jsonObject.getString("expires_in");
        // 防止代码运行超时,提前1分钟让微信token失效
        redisTemplate.opsForValue().set("自定义存入redis中的key", accessToken, Integer.valueOf(expires_in) - 60, TimeUnit.SECONDS);
        return accessToken;
    }

    /**
     * @Description: 尚泽商学院推送客服消息
     * @date: 2019/7/12 11:25
     * @param: [prepay_id, data]
     * @return: void
     */
    public void sxyPushCustomerMsg(String touser, String accesstoken, Object data) {
        StringBuilder requestUrl = new StringBuilder("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=");
        requestUrl.append(accesstoken);
        JSONObject json = new JSONObject();
        json.put("touser", touser);//设置openid
        json.put("msgtype", "text");//设置模板消息内容
        json.put("text", data);//设置模板消息内容
        log.info("推送消息:" + json.toString());
        Map<String, Object> map = null;
        try {
            HttpClient client = HttpClientBuilder.create().build();//构建一个Client
            HttpPost post = new HttpPost(requestUrl.toString());//构建一个POST请求
            StringEntity s = new StringEntity(json.toString(), "UTF-8");
            s.setContentEncoding("UTF-8");
            s.setContentType("application/json; charset=UTF-8");
            post.setEntity(s);//设置编码,不然模板内容会乱码
            HttpResponse response = client.execute(post);//提交POST请求
            HttpEntity result = response.getEntity();//拿到返回的HttpResponse的"实体"
            String content = EntityUtils.toString(result);
            System.out.println(content);//打印返回的消息
            JSONObject res = JSONObject.fromObject(content);//转为json格式
            if (res != null && "ok".equals(res.get("errmsg"))) {
                log.info("客服消息推送成功");
            } else {
                //封装一个异常
                StringBuilder sb = new StringBuilder("客服消息推送失败\n");
                sb.append(res.toString());
                throw new Exception(sb.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @Description: 推送模板消息消息
     * @date: 2019/7/12 11:25
     * @param: [prepay_id, data]
     * @return: void
     */
    public void wxProPushTelMsg(String touser, String accesstoken, String prepay_id, Object data) {
//        StringBuilder requestUrl = new StringBuilder("https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=");
        StringBuilder requestUrl = new StringBuilder("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=");
//        StringBuilder requestUrl = new StringBuilder("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=");
        requestUrl.append(accesstoken);
        JSONObject json = new JSONObject();
        json.put("touser", touser);//设置openid
//        json.put("template_id", admin_template_id);//设置模板id
//        json.put("form_id", prepay_id);//设置formid
//        json.put("data", data);//设置模板消息内容
        json.put("msgtype", "text");//设置模板消息内容
        json.put("text", data);//设置模板消息内容
        log.info("推送消息:" + json.toString());
//        json.put("page", "pages/index/main");//跳转微信小程序页面路径(非必须)
        Map<String, Object> map = null;
        try {
            HttpClient client = HttpClientBuilder.create().build();//构建一个Client
            HttpPost post = new HttpPost(requestUrl.toString());//构建一个POST请求
            StringEntity s = new StringEntity(json.toString(), "UTF-8");
            s.setContentEncoding("UTF-8");
            s.setContentType("application/json; charset=UTF-8");
            post.setEntity(s);//设置编码,不然模板内容会乱码
            HttpResponse response = client.execute(post);//提交POST请求
            HttpEntity result = response.getEntity();//拿到返回的HttpResponse的"实体"
            String content = EntityUtils.toString(result);
            System.out.println(content);//打印返回的消息
            JSONObject res = JSONObject.fromObject(content);//转为json格式
            //把信息封装到map
//            map = MdzwUtils.parseJSON2Map(res);
            if (res != null && "ok".equals(res.get("errmsg"))) {
                System.out.println("模版消息发送成功");
            } else {
                //封装一个异常
                StringBuilder sb = new StringBuilder("模版消息发送失败\n");
                sb.append(map.toString());
                throw new Exception(sb.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 第八步:rocketMq的工具类

package com.shangze.third.rocketMQ;

import com.alibaba.fastjson.JSONObject;
import xxx.xxx.xxx.utils.FastJsonUtil;
import xxx.xxx.xxx.rocketMQ.config.MqConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Description:
 * @Date: Created in 13:41 2020/4/7
 */
@Component
@Slf4j
public class PushMsgRocketUtil {
    @Autowired
    private DefaultMQProducer mqProducer;

    /**
     * @Description: 发消息
     * @date: 17:46 2021/01/30
     * @param: [topic, tags, keys, object,level(自定义的,延时的时间)]
     * @return: void
     */
    public void pushMsg(String topic, String tags, String keys, byte[] body, int level) {
        String s = "发送消息:tag=" + tags ;
        try {

            //mq发送
            Message sendMsg = new Message(topic, tags, keys, body);
            if (level > 0){
                s =s+",延时消息处理level="+ level;
                sendMsg.setDelayTimeLevel(level);
            }
            SendResult sendResult = mqProducer.send(sendMsg);
            log.info(s+ ",发送状态:" + sendResult.getSendStatus());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @Description: 
     * @date: 2020/4/8 13:58
     * @param: targetMemberId,
     * @param: orderType,
     * @param: orderId]
     * @return: void
     */
    public void pushToGzhByType(int targetMemberType, int orderType, String orderId) {
       
        // 最终的openid字符串
        StringBuilder sbuilder = new StringBuilder();
        // todo 自己的逻辑......
        String targetOpenidStr = sbuilder.toString();
        if(StringUtils.isBlank(targetOpenidStr)){
            return;
        }
        if (targetOpenidStr.substring(targetOpenidStr.length() - 1, targetOpenidStr.length()).equals(",")) {
            targetOpenidStr = targetOpenidStr.substring(0, targetOpenidStr.length() - 1);
        }
        try {
            JSONObject object = new JSONObject();
            //与监听中的messageExt.getBody()中的key值对应
            object.put("targetOpenidStr", targetOpenidStr); 
            object.put("targetMemberType", targetMemberType);
            object.put("orderType", orderType);
            //mq发送
            Message sendMsg = new Message(MqConfig.TOPIC_GZH, "push_gzh_template", orderId, FastJsonUtil.beanToJson(object).getBytes("utf-8"));
            mqProducer.send(sendMsg);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

第九步:测试推送

//入参均为自定义,根据自己的业务逻辑来写
public void test(int targetMemberType, int orderType, String orderId) {
   pushMsgRocketUtil.pushToGzhByType(targetMemberType, orderType, orderId);
}

//入参均为自定义,根据自己的业务逻辑来写
public void pushMsgRocketUtil(String orderParentId) throws UnsupportedEncodingException {
        // 清空购物车
        JSONObject object = new JSONObject();
        List<String> strings = new ArrayList<>();
        strings.add("365320011394322432");
        object.put("goodsIdList", strings);
        object.put("memberId", "235657896754321");
        pushMsgRocketUtil.pushMsg(MqConfig.MALL, MqConfig.DEL_CART, "", FastJsonUtil.beanToJson(object).getBytes("utf-8"), 0);
        pushMsgRocketUtil.pushMsg(MqConfig.MALL, MqConfig.CLOSE_MALL_ORDER, orderParentId, orderParentId.getBytes("utf-8"),"24(需要延时的时间)");
        pushMsgRocketUtil.pushMsg(MqConfig.MALL, MqConfig.RECEIPT_MALL_ORDER, orderParentId, orderParentId.getBytes("utf-8"), 12(需要延时的时间));
    }

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要详细了解RocketMQ消息推送教程,你可以通过访问官方网站上的文档来获取更多信息。 在该文档中,你将找到详细的操作步骤和示例代码。 首先,你需要在项目的pom文件中引入RocketMQ的jar包。具体操作如下:将以下代码添加到pom文件的dependencies标签中: ```xml <!--rocketmq--> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.2.0</version> </dependency> ``` 接下来,你需要设置RocketMQ的安装目录和RocketMQ的地址。你可以通过设置环境变量或在代码中进行设置。例如,在Windows系统中,你可以设置ROCKETMQ_HOME环境变量为RocketMQ的安装目录的上一级目录。同时,你需要设置NAMESRV_ADDR环境变量为RocketMQ的地址,例如localhost:9876。 一旦你完成了这些准备工作,你可以开始使用RocketMQ进行消息推送。你可以根据官方文档中的示例代码来编写你的应用程序。文档中详细介绍了如何创建Producer、发送消息和处理发送结果等操作。 通过这些步骤,你就可以开始使用RocketMQ进行消息推送了。记得参考官方文档以获取更多详细信息和示例代码。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [分布式消息队列RocketMQ详细下载安装教程](https://blog.csdn.net/weixin_45703155/article/details/126395300)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [springBoot项目部署rocketmq使用mq消息对了实现微信公众号客服消息推送](https://blog.csdn.net/FengRenYuanDeFZ/article/details/114577203)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值