【微信公众号推送小程序消息通知】--下发统一消息接口被回收后新方案
序言
由于微信小程序长期订阅的消息模板和下发统一消息推送接口全部失效以后,对于小程序的消息推送可以往公众号推可以使用本文章方案。在网上看了挺多方案,有用用户列表做匹配的等,最终觉得通过关注事件触发的方案是最省事。
准备
1、微信公众平台注册服务号(订阅号是不可以推送的)与小程序,两者都需要认证并且认证主体是一致
2、微信开放平台注册账号(该账号也需要认证),绑定小程序与公众号
3、公众号根据想要的模板消息绑定服务类目,去模板消息中先挑选你的模板消息。(如果是刚注册的公众号还需要去新的功能页面添加模板消息功能,需要微信审核,不过很快)
4、微信公众号绑定小程序
5、小程序与公众号配置服务器的ip地址白名单
6、公众号配置服务器地址
整体实现流程
通过在开放平台绑定的公众号与小程序后,我们在调用微信code2Session接口的时候会返回unionid,这个unionid就是推送的关键。
- 用到微信接口:
1、关注事件推送:用关注事件推送接口文档地址
2、查询用户基础信息:用户基础信息接口文档地址
3、获取accessToken:获取accessToken接口文档地址
4、消息模板推送:消息模板推送接口文档地址
实现代码(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 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 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() .eq(BusWxMpUser::getUnionid, user.getUnionid())); if (null != wxMpUser) { List 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); }
- 业务代码调用demo
- 微信关注事件处理类
- 微信消息路由配置类
- 公众号接入服务器开发的代码
- 封装推送工具类
- 先在配置文件yml配置公众号信息
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。