草庐IT

微信小程序消息推送

Jiozg 2023-04-14 原文


简介

微信小程序发送消息推送到用户微信上

基础流程

  1.  用户登录 :获取微信提供的openid
  2.  开发者去微信公众平台申请模板:获得模板id
  3. 授权消息推送:在小程序中调用wx.requestSubscribeMessage方法
  4. 成功后将数据保存到后台 消息推送表
  5. 在需要发送消息推送时:查询 消息推送表 如果有,使用 消息推送表 的数据调用接口subscribeMessage.send

细节流程

1.1用户微信登录(缓存opid)
1.2用户普通登录(无opid)


2 消息推送申请
2.1用户授权
2.1.1无opid(弹框要求 微信登录(类似第一步)
2.1.2有opid(继续
2.2获得了授权的模板id和opid
3传输到后台,后台存储到消息推送表,参数:模板id,opid,用户名称,身份证。默认参数:是否发送为N,创建时间,主键 ,发送时间为空
4后台定时器,查询到要发送的用户时,查询消息推送表,修改发送状态为Y,更新发送时间,然后发送微信小程序消息推送

代码

1用户微信小程序登录

wx.login({
        success: res => {
          console.log(res);
          // 发送 res.code 到后台换取 openId, sessionKey, unionId  
          request.post('后台用小程序id和密钥获取Openid的接口.do', {
            code: res.code
          }).then((res) => {
            console.log(res);
            let result = JSON.parse(res.result);
            wx.setStorageSync('openid',result.openid)//缓存openid
            that.setData({
              sessionKey: result.session_key
            })
          });
        }
      })

2 小程序消息推送授权

let templateId = '模板id';
wx.requestSubscribeMessage({
      tmplIds: [templateId],
      success (res) {
        console.log(res);
        if(res.模板id =='reject'){//被拒绝

        }else{//同意
//获取缓存的openid,可能是之前用户登录时存放的
          let opid = wx.getStorageSync('openid');
          //如果有OPID,直接发送
          if(opid){
//执行保存到后台的操作
            that.saveSubMssage(opid,templateId);
          }else{
            
              wx.showToast({
                title: '需要关联微信账号',
                icon: 'success',
                duration: 2000
              })
//和登录授权一样
              wx.login({
                success: res => {
                  console.log(res);
                  // 发送 res.code 到后台换取 openId, sessionKey, unionId  
                  request.post('后台换取用户id的接口', {
                    code: res.code
                  }).then((res) => {
//得到openid
                    let result = JSON.parse(res.result);
                    wx.setStorageSync('openid',result.openid)
                    opid=res.openid;
//执行保存到后台的操作
                    that.saveSubMssage(opid,templateId);
                  });
                }
              })
            }
        }
      },
      error(res){
        console.log(res);
        wx.showToast({
          title: '授权出现错误',
          icon: 'none',
          duration: 2000
        })
      }
    })
saveSubMssage(openid,tmplIds){
    let that = this;
    request.Post('后台保存用户同意消息推送的接口.do', {
      openId: openid,//用户openid
      templateId: tmplIds,//模板id
      userName: encodeURI(that.data.userName),//中文乱码处理
      idCard: that.data.idCard//身份证
    }).then((res) => {
      console.log(res);
      
      wx.showToast({
        title: '授权成功',
        icon: 'success',
        duration: 2000
      })


//退出页面
      setTimeout(function() {
          wx.navigateBack({ changed: true });
      }, 2000);
    });

3 后台保存用户同意消息推送的接口

 @RequestMapping(value="/SaveMessageAuthority.do" ,produces = "application/json;charset=UTF-8")
    @ResponseBody
    public String SaveMessageAuthority(String openId,String templateId,String userName ,String idCard) throws Exception {
        try {
            WeChatMessageAuthorityPO weChatMessageAuthority = new WeChatMessageAuthorityPO();
            weChatMessageAuthority.setOpenId(openId);
            weChatMessageAuthority.setTemplateId(templateId);
            weChatMessageAuthority.setIdCard(idCard);
//            String temp = request.getParameter("studentName");
            if(StringUtils.isNotEmpty(userName)){
                userName = java.net.URLDecoder.decode(userName,"UTF-8");
                weChatMessageAuthority.setUserName(userName);
            }
            weChatMessageAuthority.setCreateDate(new Date());
            weChatMessageAuthority.setIsSend(BaseStaticParameter.NO);
            iWxMassageAuthorityService.saveOrUpdate(weChatMessageAuthority);

        }catch (Exception e){
            e.printStackTrace();
            return "false";
        }

        return "true";
    }

4 后台发送推送信息

public static boolean sendNearRemindMessage(String openId,String serveName,String windowName,String lineNumber,String waitNumber,String msg) throws Exception {

        WxMaSubscribeMessage subscribeMessage = new WxMaSubscribeMessage();

        //跳转小程序页面路径
        subscribeMessage.setPage("pages/index/index");
        //模板消息id
        subscribeMessage.setTemplateId(WxMaConfiguration.templateId);
        //给谁推送 用户的openid (可以调用根据code换openid接口)
        subscribeMessage.setToUser(openId);
        //==========================================创建一个参数集合========================================================
        ArrayList<WxMaSubscribeData> wxMaSubscribeData = new ArrayList<>();

//        订阅消息参数值内容限制说明
//              ---摘自微信小程序官方:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
//        参数类别 	参数说明 	参数值限制 	   说明
//        thing.DATA 	事物 	20个以内字符 	可汉字、数字、字母或符号组合
//        number.DATA 	数字 	32位以内数字 	只能数字,可带小数
//        letter.DATA 	字母 	32位以内字母 	只能字母
//        symbol.DATA 	符号 	5位以内符号 	只能符号
//        character_string.DATA 	字符串 	32位以内数字、字母或符号 	可数字、字母或符号组合
//        time.DATA 	时间 	24小时制时间格式(支持+年月日) 	例如:15:01,或:2019年10月1日 15:01
//        date.DATA 	日期 	年月日格式(支持+24小时制时间) 	例如:2019年10月1日,或:2019年10月1日 15:01
//        amount.DATA 	金额 	1个币种符号+10位以内纯数字,可带小数,结尾可带“元” 	可带小数
//        phone_number.DATA 	电话 	17位以内,数字、符号 	电话号码,例:+86-0766-66888866
//        car_number.DATA 	车牌 	8位以内,第一位与最后一位可为汉字,其余为字母或数字 	车牌号码:粤A8Z888挂
//        name.DATA 	姓名 	10个以内纯汉字或20个以内纯字母或符号 	中文名10个汉字内;纯英文名20个字母内;中文和字母混合按中文名算,10个字内
//        phrase.DATA 	汉字 	5个以内汉字 	5个以内纯汉字,例如:配送中

        WxMaSubscribeData wxMaSubscribeData1 = new WxMaSubscribeData();
        wxMaSubscribeData1.setName("thing1");
        wxMaSubscribeData1.setValue(serveName);
        wxMaSubscribeData.add(wxMaSubscribeData1);

        WxMaSubscribeData wxMaSubscribeData2 = new WxMaSubscribeData();
        wxMaSubscribeData2.setName("thing6");
        wxMaSubscribeData2.setValue(windowName);
        wxMaSubscribeData.add(wxMaSubscribeData2);

        WxMaSubscribeData wxMaSubscribeData3 = new WxMaSubscribeData();
        wxMaSubscribeData3.setName("character_string2");
        wxMaSubscribeData3.setValue(lineNumber);
        wxMaSubscribeData.add(wxMaSubscribeData3);

        WxMaSubscribeData wxMaSubscribeData4 = new WxMaSubscribeData();
        wxMaSubscribeData4.setName("number3");
        wxMaSubscribeData4.setValue(waitNumber);
        wxMaSubscribeData.add(wxMaSubscribeData4);

        WxMaSubscribeData wxMaSubscribeData5 = new WxMaSubscribeData();
        wxMaSubscribeData5.setName("thing5");
        wxMaSubscribeData5.setValue(msg);//"快到您了,请关注窗口和叫号情况"
        wxMaSubscribeData.add(wxMaSubscribeData5);

        //把集合给大的data
        subscribeMessage.setData(wxMaSubscribeData);
        //=========================================封装参数集合完毕========================================================

        try {
            System.out.println(JsonUtil.toJSONString(subscribeMessage));
            //获取微信小程序配置:

            final WxMaService wxService = WxMaConfiguration.getMaService(WxMaConfiguration.appid);
            //进行推送
            wxService.getMsgService().sendSubscribeMsg(subscribeMessage);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
        }
        return false;
    }

5 微信maven(微信调用方式可选)


        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-miniapp</artifactId>
            <version>3.6.0</version>
        </dependency>

6 WxMaConfiguration



import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
import cn.binarywang.wx.miniapp.bean.WxMaMessage;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateData;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.io.File;
import java.util.Map;

/**
 * create by zhaojiong
 * 22-8-16
 */
@Configuration
public class WxMaConfiguration {

    //叫号
    public final static String jh_templateId = "
消息模板id";
    //排队
    public final static String pd_templateId = "消息模板id";
    public final static String appid = "按情况填写";
    public final static String secret = "按情况填写";
    public final static String token = "按情况填写";
    public final static String aesKey = "按情况填写";
    public final static String msgDataFormat = "JSON";
//
    private static Map<String, WxMaMessageRouter> routers = Maps.newHashMap();
    private static Map<String, WxMaService> maServices = Maps.newHashMap();
//
//
    public static WxMaService getMaService(String appid) {
        WxMaService wxService = maServices.get(appid);
        if (wxService == null) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
        }

        return wxService;
    }
//
    public static WxMaMessageRouter getRouter(String appid) {
        return routers.get(appid);
    }
//
//

    @PostConstruct
    public void init() {

        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid(appid);
        config.setSecret(secret);
        config.setToken(token);
        config.setAesKey(aesKey);
        config.setMsgDataFormat(msgDataFormat);

        WxMaService service = new WxMaServiceImpl();
        service.setWxMaConfig(config);
        routers.put(appid, this.newRouter(service));
        maServices.put(appid, service);

    }
//
    private WxMaMessageRouter newRouter(WxMaService service) {
        final WxMaMessageRouter router = new WxMaMessageRouter(service);
        router
                .rule().handler(logHandler).next()
                .rule().async(false).content("模板").handler(templateMsgHandler).end()
                .rule().async(false).content("文本").handler(textHandler).end()
                .rule().async(false).content("图片").handler(picHandler).end()
                .rule().async(false).content("二维码").handler(qrcodeHandler).end();
        return router;
    }

    private final WxMaMessageHandler templateMsgHandler = new WxMaMessageHandler() {
        @Override
        public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context, WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
            service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder()
                    .templateId("此处更换为自己的模板id")
                    .formId("自己替换可用的formid")
                    .data(Lists.newArrayList(
                            new WxMaTemplateData("keyword1", "339208499", "#173177")))
                    .toUser(wxMessage.getFromUser())
                    .build());
            return null;
        }
    };

    private final WxMaMessageHandler logHandler = new WxMaMessageHandler() {
        @Override
        public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context, WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
            System.out.println("收到消息:" + wxMessage.toString());
            service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
                    .toUser(wxMessage.getFromUser()).build());
            return null;
        }
    };

    private final WxMaMessageHandler textHandler = new WxMaMessageHandler() {
        @Override
        public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context, WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
            service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
                    .toUser(wxMessage.getFromUser()).build());
            return null;
        }
    };

    private final WxMaMessageHandler picHandler = new WxMaMessageHandler() {
        @Override
        public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context, WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
            try {
                WxMediaUploadResult uploadResult = service.getMediaService()
                        .uploadMedia("image", "png",
                                ClassLoader.getSystemResourceAsStream("tmp.png"));
                service.getMsgService().sendKefuMsg(
                        WxMaKefuMessage
                                .newImageBuilder()
                                .mediaId(uploadResult.getMediaId())
                                .toUser(wxMessage.getFromUser())
                                .build());
            } catch (WxErrorException e) {
                e.printStackTrace();
            }

            return null;
        }
    };

    private final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() {
        @Override
        public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context, WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
            try {
                final File file = service.getQrcodeService().createQrcode("123", 430);
                WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file);
                service.getMsgService().sendKefuMsg(
                        WxMaKefuMessage
                                .newImageBuilder()
                                .mediaId(uploadResult.getMediaId())
                                .toUser(wxMessage.getFromUser())
                                .build());
            } catch (WxErrorException e) {
                e.printStackTrace();
            }

            return null;
        }
    };

}

有关微信小程序消息推送的更多相关文章

  1. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  2. ruby - 使用 Ruby 通过 Outlook 发送消息的最简单方法是什么? - 2

    我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=

  3. Ruby - 如何将消息长度表示为 2 个二进制字节 - 2

    我正在使用Ruby,我正在与一个网络端点通信,该端点在发送消息本身之前需要格式化“header”。header中的第一个字段必须是消息长度,它被定义为网络字节顺序中的2二进制字节消息长度。比如我的消息长度是1024。如何将1024表示为二进制双字节? 最佳答案 Ruby(以及Perl和Python等)中字节整理的标准工具是pack和unpack。ruby的packisinArray.您的长度应该是两个字节长,并且按网络字节顺序排列,这听起来像是n格式说明符的工作:n|Integer|16-bitunsigned,network(bi

  4. 微信小程序通过字典表匹配对应数据 - 2

    前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立

  5. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  6. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  7. ruby-on-rails - 在 Flash 警报 Rails 3 中显示错误消息 - 2

    如果我在模型中设置验证消息validates:name,:presence=>{:message=>'Thenamecantbeblank.'}我如何让该消息显示在闪光警报中,这是我迄今为止尝试过的方法defcreate@message=Message.new(params[:message])if@message.valid?ContactMailer.send_mail(@message).deliverredirect_to(root_path,:notice=>"Thanksforyourmessage,Iwillbeintouchsoon")elseflash[:error]

  8. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

  9. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  10. ruby-on-rails - 闪存消息存储在哪里? - 2

    我以为它们存储在cookie中-但不,检查cookie没有任何结果。session也不存储它们。那么,我在哪里可以找到它们?我需要这个来直接设置它们(而不是通过flashhash)。 最佳答案 它们存储在inyoursessionstore.自rails2.0以来的默认设置是cookie存储,但请检查config/initializers/session_store.rb以检查您是否使用默认设置以外的东西。 关于ruby-on-rails-闪存消息存储在哪里?,我们在StackOverf

随机推荐