【微信公众号推送小程序消息通知】--下发统一消息接口被回收后新方案

序言

由于微信小程序长期订阅的消息模板和下发统一消息推送接口全部失效以后,对于小程序的消息推送可以往公众号推可以使用本文章方案。在网上看了挺多方案,有用用户列表做匹配的等,最终觉得通过关注事件触发的方案是最省事。

准备

1、微信公众平台注册服务号(订阅号是不可以推送的)与小程序,两者都需要认证并且认证主体是一致

2、微信开放平台注册账号(该账号也需要认证),绑定小程序与公众号
在这里插入图片描述
3、公众号根据想要的模板消息绑定服务类目,去模板消息中先挑选你的模板消息。(如果是刚注册的公众号还需要去新的功能页面添加模板消息功能,需要微信审核,不过很快)
在这里插入图片描述
4、微信公众号绑定小程序
在这里插入图片描述
5、小程序与公众号配置服务器的ip地址白名单
在这里插入图片描述
6、公众号配置服务器地址
在这里插入图片描述

整体实现流程

通过在开放平台绑定的公众号与小程序后,我们在调用微信code2Session接口的时候会返回unionid,这个unionid就是推送的关键。

实现代码(Java)

这里使用第三方工具包Wx-Java(非常方便),直接实现推送代码。具体源码可以浏览https://gitee.com/binary/weixin-java-tools

  • 先在配置文件yml配置公众号信息
# 公众号配置
wx:
  mp:
    appId: xiaochengxuappid
    secret: xiaochengxusecrect
    token: xiaochengxutoken
    aesKey:  xiaochengxuaes
    # token存储在redis
    config-storage:
      type: RedisTemplate
  • 封装推送工具类
	/**
     * 微信公众号推送模板消息
     *
     * @param openid       用户openid
     * @param templateData 模板参数
     */
    public void sendTemplateMsg(String openid, List<WxMpTemplateData> templateData) {
        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                .toUser(openid)
                // 模板id
                .templateId(templateId)
                // 跳转小程序appid,跳转路径
                .miniProgram(new WxMpTemplateMessage.MiniProgram(weAppAppId, "", false))
                // 模板参数
                .data(templateData)
                .build();
        try {
            log.debug("微信公众号推送模板消息入参:{}", templateMessage);
            // 成功返回msgId,否则都是抛异常
            wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
        } catch (WxErrorException e) {
            log.error("微信公众号推送模板消息异常", e);
        }
    }
  • 公众号接入服务器开发的代码
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author quan
 * @date 2023/11/7 18:19
 */
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/wx")
public class WxPortalController {
    @Autowired
    private final WxMpService wxService;
    @Autowired
    private final WxMpMessageRouter messageRouter;

    @GetMapping(produces = "text/plain;charset=utf-8")
    public String authGet(@PathVariable String appid,
                          @RequestParam(name = "signature", required = false) String signature,
                          @RequestParam(name = "timestamp", required = false) String timestamp,
                          @RequestParam(name = "nonce", required = false) String nonce,
                          @RequestParam(name = "echostr", required = false) String echostr) {
        log.info("接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, timestamp, nonce, echostr);
        if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
            throw new IllegalArgumentException("请求参数非法,请核实!");
        }

        if (!this.wxService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
        }

        if (wxService.checkSignature(timestamp, nonce, signature)) {
            return echostr;
        }

        return "非法请求";
    }

    @PostMapping(produces = "application/xml; charset=UTF-8")
    public String post(@PathVariable String appid,
                       @RequestBody String requestBody,
                       @RequestParam("signature") String signature,
                       @RequestParam("timestamp") String timestamp,
                       @RequestParam("nonce") String nonce,
                       @RequestParam("openid") String openid,
                       @RequestParam(name = "encrypt_type", required = false) String encType,
                       @RequestParam(name = "msg_signature", required = false) String msgSignature) {
        log.info("接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                openid, signature, encType, msgSignature, timestamp, nonce, requestBody);

        if (!this.wxService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
        }

        if (!wxService.checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
        }

        String out = null;
        if (encType == null) {
            // 明文传输的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }

            out = outMessage.toXml();
        } else if ("aes".equalsIgnoreCase(encType)) {
            // aes加密的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
                    timestamp, nonce, msgSignature);
            log.debug("消息解密后内容为:{} ", inMessage);
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }

            out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
        }

        log.debug("组装回复信息:{}", out);
        return out;
    }

    private WxMpXmlOutMessage route(WxMpXmlMessage message) {
        try {
            return this.messageRouter.route(message);
        } catch (Exception e) {
            log.error("路由消息时出现异常!", e);
        }

        return null;
    }
}

  • 微信消息路由配置类
/**
 * @author quan
 * @date 2023/11/7 18:23
 */
@AllArgsConstructor
@Configuration
public class WxMpConfiguration {
    private final SubscribeHandler subscribeHandler;

    @Bean
    public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);

        // 关注事件
        newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();

        return newRouter;
    }
}
  • 微信关注事件处理类
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tfcs.web.domain.bus.BusWxMpUser;
import com.tfcs.web.service.BusWxMpUserService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 关注处理器
 *
 * @author quan
 * @date 2023/9/15 14:05
 */
@Slf4j
@Component
public class SubscribeHandler implements WxMpMessageHandler {
    @Autowired
    private BusWxMpUserService wxMpUserService;

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService weixinService,
                                    WxSessionManager sessionManager) {

        log.info("新关注用户 OPENID: " + wxMessage.getFromUser());

        // 获取微信用户基本信息
        try {
            WxMpUser userWxInfo = weixinService.getUserService()
                    .userInfo(wxMessage.getFromUser(), null);
            if (userWxInfo != null) {
                // TODO 先检查是否存在该用户,不存在再存到数据库
            }
        } catch (WxErrorException e) {
            log.error("微信公众号获取用户信息异常:", e);
            if (e.getError().getErrorCode() == 48001) {
                log.info("该公众号没有获取用户信息权限!");
            }
        }
        return null;
    }
}
  • 业务代码调用demo
// 通过unionid查出公众号openid
BusWxMpUser wxMpUser = wxMpUserService.getOne(new LambdaQueryWrapper<BusWxMpUser>()
         .eq(BusWxMpUser::getUnionid, user.getUnionid()));
 if (null != wxMpUser) {
     List<WxMpTemplateData> templateData = new ArrayList<>(5);
     // 对应消息模板的key
     templateData.add(new WxMpTemplateData("character_string2", event.getFlightNo()));
     templateData.add(new WxMpTemplateData("thing10", event.getStartPlace()));
     templateData.add(new WxMpTemplateData("thing11", event.getDestPlace()));
     templateData.add(new WxMpTemplateData("time3", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, event.getFlightStartTime())));
     templateData.add(new WxMpTemplateData("thing9", "请及时处理关注事件"));
     weChatUtil.sendTemplateMsg(wxMpUser.getOpenid(), templateData);
 }
  • 推送效果
    在这里插入图片描述
  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 21
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值