微信公众号下发统一消息

获取公众号或小程序 AccessToken 地址 get请求

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET

推送公众号模板消息接口地址 POST请求

https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=AccessToken

注意:

  1. 如果根据小程序 openid 推送, 公众号与小程序必须要进行关联

  2. 发送时需要缓存 AccessToken , 因为每天2000次, 推送消息时必须是拿到的小程序的AccessToken

  3. "touser":"oEqaV4uFSCSWzVeBBod24KwwbsTE" 可以是小程序或者公众号的 openid

公众号下发统一消息 数据格式

{
    "touser":"oEqaV4uFSCSWzVeBBod24KwwbsTE",
    "mp_template_msg":{
        "appid":"wxa8955d5d443d3e9f",
        "template_id":"ucOg12u77dYhFLSJr0uuhSkvUDZJROrNDiEE-Y4lnYM",
        "url":"http://weixin.qq.com",
        "miniprogram":{
            "appid":"wx66622d29b6252da8",
            "pagepath":"pages/parkingRecordId/parkingRecordId?scene=123"
        },
        "data":{
            "first":{
                "value":"恭喜你购买成功!",
                "color":"#173177"
            },
            "keyword1":{
                "value":"巧克力",
                "color":"#173177"
            },
            "keyword2":{
                "value":"39.8元",
                "color":"#173177"
            },
            "remark":{
                "value":"欢迎再次购买!",
                "color":"#173177"
            }
        }
    }
} 

微信封装的发送方式-->基于公众号openid发送

   String openid = "o20RG6sb4bBAlndFStIUiuy1WzeE";
        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                .toUser(openid)//要推送的用户openid
                .templateId("1zQSJMyL6hACI5FCElehHE9IZgR3PO82saTBeFBUEFg")//模板id
                .url("http://ggkt2.vipgz1.91tunnel.com/#/pay/"+5)//点击模板消息要访问的网址
                .build();
        //3,如果是正式版发送消息,,这里需要配置你的信息
        templateMessage.addData(new WxMpTemplateData("first", "尊敬的用户,您的爱车已驶入无人收费停车场。该车场不支持电子发票、预约车位。", "#272727"));
        templateMessage.addData(new WxMpTemplateData("keyword1", "渝D***36", "#272727"));
        templateMessage.addData(new WxMpTemplateData("keyword2", "高科****业园", "#272727"));
        templateMessage.addData(new WxMpTemplateData("keyword3", "2023-03-31 08:33:16", "#272727"));
        templateMessage.addData(new WxMpTemplateData("keyword4", "你有2~5元停车立减券可换,本次停车可直接抵扣!点击查看>>>>", "#f1515c"));
        templateMessage.addData(new WxMpTemplateData("remark", "感谢你使用公众号,如有疑问,随时咨询!", "#272727"));
        System.err.println(templateMessage.toJson());
        //发起推送
        try {
            String msg = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
            System.out.println("推送成功:" + msg);
        } catch (Exception e) {
            System.out.println("推送失败:" + e.getMessage());
            e.printStackTrace();
        }

自己封装的统一下发-->公众号小程序openid都可以发送-->推荐使用

 ArrayList<GZHVo.Keyword> keywords = new ArrayList();
            GZHVo.First first = new GZHVo.First("尊敬的用户,您的爱车已驶入无人收费停车场。", "#272727");
            GZHVo.Keyword keyword1 = new GZHVo.Keyword(StringUtils.isEmpty(carPlate) ? "无" : carPlate.replace(carPlate.substring(2, 5), "****"), "#272727");//车牌号
            GZHVo.Keyword keyword2 = new GZHVo.Keyword(StringUtils.isEmpty(carName) ? "无" : WxUtil.nameMask(carName), "#272727");//停车场
            GZHVo.Keyword keyword3 = new GZHVo.Keyword(StringUtils.isEmpty(arriveTime) ? "无" : DateUtils.toyyyy_MM_dd_HHmmss(arriveTime), "#272727");//入场时间
            GZHVo.Remark remark = new GZHVo.Remark("感谢你使用公众号,如有疑问,随时咨询!", "#f1515c");//备注
            keywords.add(keyword1);
            keywords.add(keyword2);
            keywords.add(keyword3);
            GZHVo.data data = new GZHVo.data(first, remark, keywords);

            GZHVo.mp_template_msg mp_template_msg = new mp_template_msg()
                    .setAppid(WeChatConfig.WX_APPID)
                    .setTemplate_id(weChatConfig.getGo_templateId())
                    .setUrl("")
                    .setData(data)
                    .setMiniprogram(new Miniprogram(carowner.getAppid(), "pages/parkingRecordId/?scene=" + parkingRecord.getId()));

            GZHJsonRootBean gzhJsonRootBean = new GZHJsonRootBean()
                    .setTouser(carowner.getOpenid())
                    .setMp_template_msg(mp_template_msg);

            //发起推送
            try {
                Map<String, Object> sendMessage_wx = WxUtil.sendMessage(gzhJsonRootBean, WxUtil.reidsCacheAccessToken(redisTemplate));
                msgGCH = true;
                log.info("入场公众号消息内容: {}", gzhJsonRootBean.toString());
                System.out.println("推送入场公众号消息 成功:" + sendMessage_wx);
            } catch (Exception e) {
                System.err.println("推送入场公众号消息 失败:" + e.getMessage());
                e.printStackTrace();
            }
        }

推送公众号模板消息-->基于公众号openid发送

GZHVo.First first = new GZHVo.First("你在虚拟仿真系统有一笔消息待处理", "");
        ArrayList<GZHVo.Keyword> keywords = new ArrayList();
        GZHVo.Keyword keyword1 = new GZHVo.Keyword("测试名称", "#173177");
        GZHVo.Keyword keyword2 = new GZHVo.Keyword("考试评价", "#173177");
        GZHVo.Keyword keyword3 = new GZHVo.Keyword(LocalDateTime.now().toString(), "#173177");
        GZHVo.Keyword keyword4 = new GZHVo.Keyword("考试成绩评分", "#173177");
        keywords.add(keyword1);
        keywords.add(keyword2);
        keywords.add(keyword3);
        keywords.add(keyword4);

        GZHVo.Remark remark = new GZHVo.Remark("请及时前往处理", "");
        GZHVo.data data = new GZHVo.data(first, remark, keywords);
        JsonRootBean jsonRootBean = new JsonRootBean("o20RG6sb4bBAlndFStIUiuy1WzeE", "1zQSJMyL6hACI5FCElehHE9IZgR3PO82saTBeFBUEFg", "http://weixin.qq.com", new GZHVo.Miniprogram(), data);
        String accessToken = WxUtil.getAccessToken(WeChatConfig.WX_APPID, WeChatConfig.WX_SECRET);

        WxUtil.sendMessage2(accessToken,jsonRootBean);
    }

参数封装代码

@Data
@Accessors(chain = true)
public class GZHVo {
    //存储remark中的数据与颜色
    @Data
    @Accessors(chain = true)
    public static class Remark {
        private String value;
        private String color;

        public Remark(String value, String color) {
            this.value = value;
            this.color = color;
        }
    }

    //Miniprogram //小程序相关数据,无小程序可以不填,或者填充空串
    @Data
    @Accessors(chain = true)
    public static class Miniprogram {
        private String appid;
        private String pagepath;

        public Miniprogram() { }

        public Miniprogram(String appid, String pagepath) {
            this.appid = appid;
            this.pagepath = pagepath;
        }
    }

    @Data
    @Accessors(chain = true)
    public static class mp_template_msg {
        private String appid;
        private String template_id;
        private String url;
        private GZHVo.data data;
        /**
         * 跳小程序所需数据,不需跳小程序可不用传该数据
         */
        private GZHVo.Miniprogram miniprogram;

        public mp_template_msg() { }
    }

    //Keyword,中间keyword部分
    @Data
    @Accessors(chain = true)
    public static class Keyword {
        private String value;
        private String color;

        public Keyword(String value, String color) {
            this.value = value;
            this.color = color;
        }

        public Keyword() { }
    }

    //First 首个数据
    @Data
    @Accessors(chain = true)
    public static class First {
        private String value;
        private String color;

        public First(String value, String color) {
            this.value = value;
            this.color = color;
        }
    }

    //data 包含first、keyword、remark
    @Data
    @Accessors(chain = true)
    public static class data {
        private First first;
        private Keyword keyword1;
        private Keyword keyword2;
        private Keyword keyword3;
        private Keyword keyword4;
        private Keyword keyword5;
        private Keyword keyword6;
        private Remark remark;

        public data(First first, Remark remark, ArrayList<Keyword> keyword) {
            this.first = first;
            int count = 1;
            for (Keyword keyword1 : keyword) {
                if (count == 1) {
                    this.keyword1 = keyword1;
                } else if (count == 2) {
                    this.keyword2 = keyword1;
                } else if (count == 3) {
                    this.keyword3 = keyword1;
                } else if (count == 4) {
                    this.keyword4 = keyword1;
                } else if (count == 5) {
                    this.keyword5 = keyword1;
                } else if (count == 6) {
                    this.keyword6 = keyword1;
                }
                count++;
            }
            this.remark = remark;
        }

        public data() {
            super();
        }
    }

    public GZHVo() {
        super();
    }
}
/**
 * 公众号推送消息封装-->整合实体类所有数据
 */
@Data
@Accessors(chain = true)
public class GZHJsonRootBean {
    /**
     * 接收者openid
     */
    private String touser;
    /**
     * 模板id
     */
    private GZHVo.mp_template_msg mp_template_msg;



    public GZHJsonRootBean() {
    }

    public GZHJsonRootBean(String touser, GZHVo.mp_template_msg mp_template_msg) {
        this.touser = touser;
        this.mp_template_msg=mp_template_msg;
    }

}

util工具类



/**
 * 系统常量-->及工具类
 */
@Slf4j
public class WxUtil {

    //入场推送
    public static final String GZH_PUSH_MSG_GO = "GZH_PUSH_MSG_GO:";
    //出场推送
    public static final String GZH_PUSH_MSG_OUT = "GZH_PUSH_MSG_OUT:";
    //微信小程序 token
    public static final String XCX_ACCESS_TOKEN = "XCX_ACCESS_TOKEN:";
    public static final String XCX_EXPIRES_IN = "XCX_EXPIRES_IN:";


    /**
     * 用户姓名的打码隐藏加星号加*
     *
     * @return 处理完成的姓名
     */
    public static String nameMask(String name) {
        String res = "";
        if (name.length() == 2) {
            res = name.replaceAll("^.", "*");
        } else if (name.length() <= 3) {
            res = name.replaceAll("(?<=.).(?=.)", "*");
        } else if (name.length() > 3) {
            res = name.replaceAll("(?<=.).(?=..)", "*");
        }
        return res;
    }

    /**
     * redis缓存小程序的 AccessToken    过期的前10分钟刷新
     *
     * @return
     */
    public static String reidsCacheAccessToken(RedisTemplate redisTemplate) {
        //如果不等于空 或者小于600秒
        if (redisTemplate.getExpire(WxUtil.XCX_EXPIRES_IN) < 600 || StringUtils.isEmpty(redisTemplate.hasKey(WxUtil.XCX_ACCESS_TOKEN))) {
            JSONObject json = WxUtil.getAccessToken(WeChatConfig.XIAOCX_APPID, WeChatConfig.XIAOCX_APPSECRET);

            redisTemplate.opsForValue().set(WxUtil.XCX_ACCESS_TOKEN, json.get("access_token"), 7200, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(WxUtil.XCX_EXPIRES_IN, json.get("expires_in"), 7200, TimeUnit.SECONDS);

            log.info("更新redis accessToken: {}", json.get("access_token"));
            log.info("过期时间为 expiresIn: {}", json.get("expires_in"));
        }
        String accessToken = redisTemplate.opsForValue().get(WxUtil.XCX_ACCESS_TOKEN).toString();
        Long expiresIn = redisTemplate.getExpire(WxUtil.XCX_EXPIRES_IN);
        log.info("redis取出 accessToken: {}", accessToken);
        log.info("剩余过期时间 expiresIn: {}", expiresIn);
        return accessToken;
    }

//    /**
//     * 发送消息工具类-->公众号发送
//     *
//     * @return
//     */
//    public static Map<String, Object> sendMessage2(String AccessToken, JsonRootBean2 jsonRootBean2) {
//        String json = JSON.toJSONString(jsonRootBean2);
//        String info = HttpUtil.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + AccessToken, json);
//        Map<String, Object> map = (Map) JSON.parse(info);
      System.out.println(AccessToken);
//        if (map.get("errcode").equals(new Integer(0))) {
//            log.info("0,消息推送成功,用户openid: {},消息内容: {}", jsonRootBean2.getTouser(), json);
//        } else if (map.get("errcode").equals(new Integer(40003))) {
//            log.error("40003,推送消息的openid错误,用户openid: {},消息内容: {}", jsonRootBean2.getTouser(), json);
//        } else if (map.get("errcode").equals(new Integer(43004))) {
//            log.error("43004,该用户未关注 或 已取消关注公众号,用户openid: {},消息内容: {}", jsonRootBean2.getTouser(), json);
//        } //else {
            try {
                throw new WxErrorException(WxError.fromJson(info, WxType.MP));
            } catch (WxErrorException e) {
                e.printStackTrace();
            }
        }
        System.out.println(map);//{"errcode":0,"errmsg":"ok","msgid":2873391715469262849}
//        return map;
//    }

    /**
     * 发送公众号模板消息工具类-->统一下发消息
     *
     * @return
     */
    public static Map<String, Object> sendMessage(GZHJsonRootBean gzhJsonRootBean, String AccessToken) {
        String json = JSON.toJSONString(gzhJsonRootBean);
        String info = HttpUtil.post("https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=" + AccessToken, json);
        Map<String, Object> map = (Map) JSON.parse(info);
//      System.out.println(AccessToken);
        if (map.get("errcode").equals(new Integer(0))) {
            log.info("0,消息推送成功,用户openid: {},消息内容: {}", gzhJsonRootBean.getTouser(), json);
        } else if (map.get("errcode").equals(new Integer(40003))) {
            log.error("40003,推送消息的openid错误,用户openid: {},消息内容: {}", gzhJsonRootBean.getTouser(), json);
        } else if (map.get("errcode").equals(new Integer(43004))) {
            log.error("43004,该用户未关注 或 已取消关注公众号,用户openid: {},消息内容: {}", gzhJsonRootBean.getTouser(), json);
        } else {
            log.info("用户openid: {},消息内容: {}", gzhJsonRootBean.getTouser(), json);
//            try {
//                throw new WxErrorException(WxError.fromJson(info, WxType.MP));
//            } catch (WxErrorException e) {
//                e.printStackTrace();
//            }
        }
//        System.out.println(map);//{"errcode":0,"errmsg":"ok","msgid":2873391715469262849}
        return map;
    }


    /**
     * 获取access_token, 返回值
     *
     * @return
     */
    public static String getAccessToken2(String appid, String secret) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("https://api.weixin.qq.com/cgi-bin/token");
        buffer.append("?grant_type=client_credential");
        buffer.append("&appid=%s");
        buffer.append("&secret=%s");
        //请求地址设置参数
        String url = String.format(buffer.toString(), appid, secret);
        String tokenString = HttpUtil.get(url);
        String access_token = "";
        if (tokenString != null) {
            //获取access_token
            JSONObject jsonObject = JSONObject.parseObject(tokenString);
            access_token = jsonObject.getString("access_token");
        }
        return access_token;
    }

    /**
     * 获取access_token,返回 JSONObject
     *
     * @param AppId
     * @param AppSecret
     * @return
     * @throws Exception
     */
    public static JSONObject getAccessToken(String AppId, String AppSecret) {
        String access_tokenurl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        access_tokenurl = access_tokenurl.replace("APPID", AppId);
        access_tokenurl = access_tokenurl.replace("APPSECRET", AppSecret);
        String tokenString = HttpUtil.get(access_tokenurl);
        JSONObject jsonObjectToken = null;
        String access_token = "";
        if (tokenString != null) {
            //获取access_token
            jsonObjectToken = JSONObject.parseObject(tokenString);
//            access_token = jsonObject.getString("access_token");
        }
        return jsonObjectToken;
    }

    /**
     * 将微信的XML解析成 MAP 结构
     *
     * @param request
     * @return
     * @throws Exception
     */
    private Map<String, String> parseXml(HttpServletRequest request) throws Exception {
        Map<String, String> map = new HashMap<String, String>();
        InputStream inputStream = request.getInputStream();
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        Element root = document.getRootElement();
        List<Element> elementList = root.elements();
        for (Element e : elementList) {
            map.put(e.getName(), e.getText());
        }
        inputStream.close();
        inputStream = null;
        return map;
    }
}

配置类

/**
 * 读取 yml 配置
 */
@Data
@Slf4j
@Component
@ConfigurationProperties(prefix = "wechat")
public class WeChatConfig implements InitializingBean {
    private String gzh_appid;
    private String gzh_secret;

    private String xcx_appid;
    private String xcx_appSecret;


    private String go_templateId;
    private String out_templateId;
    private String arrears_templateId;


    public static String WX_APPID;
    public static String WX_SECRET;
    public static String XIAOCX_APPID;
    public static String XIAOCX_APPSECRET;
    @Override
    public void afterPropertiesSet() throws Exception {
        WX_APPID = gzh_appid;
        WX_SECRET = gzh_secret;
        XIAOCX_APPID = xcx_appid;
        XIAOCX_APPSECRET = xcx_appSecret;
        log.info("我初始化了属性值,成功了");
    }



    /**
     * 微信 bean 配置
     */
    @Component
    @Configuration
    public static class WeChatMpConfig {
        @Bean
        public WxMpConfigStorage wxMpConfigStorage() {
            WxMpDefaultConfigImpl wxMpConfigStorage = new WxMpDefaultConfigImpl();
            wxMpConfigStorage.setAppId(WeChatConfig.WX_APPID);
            wxMpConfigStorage.setSecret(WeChatConfig.WX_SECRET);
            return wxMpConfigStorage;
        }
        @Bean
        public WxMpService wxMpService() {
            WxMpService wxMpService = new WxMpServiceImpl();
            wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
            return wxMpService;
        }

    }
}

在 UniApp 开发的微信公众号 H5 页面中实现跳转到小程序的功能,需要借助微信提供的JS-SDK,特别是`wx.navigateToMiniProgram`或`wx.redirectToMiniProgram`这两个API。以下是步骤: 1. **引入微信JSSDK**: 首先,在公众号后台配置好微信开发者工具,获取到appID,然后在uni-app项目的pages中引入微信的JSBridge库,例如在index.html: ```html <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js" type="text/javascript"></script> ``` 2. **初始化JS-SDK**: 在相应的H5页面加载完成后,调用微信的`onLoad`生命周期函数,并初始化JS-SDK: ```javascript Page({ onLoad() { wx.config({ debug: false, // 是否开启调试模式,false生产环境 appId: 'your_app_id', // 必填,公众号的唯一标识 timestamp: '', // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '', // 必填,签名 jsApiList: ['checkJsApi', 'navigateToMiniProgram'] // 必填,需要使用的JS接口列表 }); wx.ready(function () { // 小程序路径,可以是一个小程序内的页面路径,也可以是统一下发的链接 let path = 'page/path/in/your/miniprogram'; // 跳转到小程序 wx.navigateToMiniProgram({ path: path, success: function(res) { console.log('跳转成功'); }, fail: function(err) { console.error('跳转失败:', err); } }); }); } }); ``` 3. **检查并授权**:在使用某些特定接口之前,需要先检查用户是否已授权,例如`wx.checkJsApi`。 记得替换上述代码中的`your_app_id`、`timestamp`、`nonceStr`和`signature`为实际获取的值。在实际项目中,这些值通常由后端提供或者通过前端获取签名函数动态生成。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值