赞
踩
需求背景:小程序下单完成之后,通过微信公众号给关注的用户推送信息、小程序和公众号的同一ID为unionId
前置条件
(1)在公众号开放平台绑定小程序和公众号是同一主体【公众账号和小程序】
(2)开通服务号模版消息接口授权使用(一般需要两到三天)
(3)公众号配置通知地址
提交配置的时候,可能会提示token无效,那是因为接口验证没有通过、代码验签实现如下:
【因为接收事件推送消息的数据包是XML格式,所以需要倒入解析的jar包】
- <xml>
- <ToUserName>< ![CDATA[toUser] ]></ToUserName>
- <FromUserName>< ![CDATA[FromUser] ]></FromUserName>
- <CreateTime>123456789</CreateTime>
- <MsgType>< ![CDATA[event] ]></MsgType>
- <Event>< ![CDATA[subscribe] ]></Event>
- </xml>
- <dependency>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- <version>1.6.1</version>
- </dependency>
代码实现
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONObject;
- import org.apache.commons.lang3.StringUtils;
- import org.dom4j.Document;
- import org.dom4j.Element;
- import org.dom4j.DocumentHelper;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.web.bind.annotation.*;
-
- import javax.servlet.http.HttpServletRequest;
- import java.io.*;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.util.Arrays;
-
- /**
- * @version 1.0
- * @description: 公众号订阅通知
- */
- @RestController
- public class SubscribeNoticeController {
-
- private static final Logger log = LoggerFactory.getLogger(SubscribeNoticeController.class);
-
- /**
- * @GetMapping 和 @PostMapping 路径名称是一样的,一个用来验证token、一个用来接收数据
- */
-
- /**
- * token 验签
- */
- @GetMapping("/noticeInfo")
- Long checkParams(@RequestParam("signature") String signature,
- @RequestParam("timestamp") String timestamp,
- @RequestParam("nonce") String nonce,
- @RequestParam("echostr") String echostr){
- String token = "和你在公众号配置中的token保持一致";
- String[] arr = {token, timestamp, nonce};
- Arrays.sort(arr);
-
- StringBuilder content = new StringBuilder();
- for (int i = 0; i < arr.length; i++) {
- content.append(arr[i]);
- }
-
- //sha1Hex 加密
- MessageDigest md = null;
- String temp = null;
- try {
- md = MessageDigest.getInstance("SHA-1");
- byte[] digest = md.digest(content.toString().getBytes());
- temp = byteToStr(digest);
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- if ((temp.toLowerCase()).equals(signature)){
- /**
- * 重点:要把接收的这个随机码返回
- */
- return Long.valueOf(echostr);
- }
- return null;
- }
-
- /**
- * 接收推送的数据
- */
- @PostMapping("/noticeInfo")
- @ResponseBody
- public String subscribeProcessor(HttpServletRequest request) throws Exception {
- BufferedReader br = request.getReader();
- String str="";
- String paramInfo = "";
- while((str = br.readLine()) != null){
- paramInfo += str;
- }
- if (StringUtils.isNotBlank(paramInfo)){
- JSONObject jsonObject = JSON.parseObject(paramInfo);
- String xmlInfo = jsonObject.getString("xmlInfo");
- paramInfo = xmlInfo;
- }
- log.info("微信公众号接收信息:{}",paramInfo);
- paramInfo = paramInfo.replaceAll(" ", "");
- Document document = DocumentHelper.parseText(paramInfo);
- Element root = document.getRootElement();
- String toUserName = root.elementText("ToUserName");
- String fromUserName = root.elementText("FromUserName");
- String createTime = root.elementText("CreateTime");
- String msgType = root.elementText("MsgType");
- String event = root.elementText("Event");
- log.info("微信公众号接收信息:{},{},{},{},{}",toUserName,fromUserName,createTime,msgType,event);
- /**
- * 处理后续的逻辑信息...
- */
- return null;
- }
-
- private static String byteToStr(byte[] byteArray){
- String strDigest = "";
- for (int i = 0; i < byteArray.length; i++) {
- strDigest += byteToHexStr(byteArray[i]);
- }
- return strDigest;
- }
-
- private static String byteToHexStr(byte mByte){
- char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A','B', 'C', 'D', 'E', 'F' };
- char[] tempArr = new char[2];
- tempArr[0] = Digit[(mByte >>> 4)& 0X0F];
- tempArr[1] = Digit[mByte & 0X0F];
- String s = new String(tempArr);
- return s;
- }
- }

至此就可以接收公众号推送的信息了、比如用户的订阅、取关事件都能有通知。
实现推送消息给用户
前面代码已经可以监听到用户的订阅、取关的事件了,因为可以通过用户订阅的事件拿到用户的FromUserName(用户的openId)信息、通过这个字段,就能查到用户的unionId、然后把openId和unionId保存到数据库、相关实现方法:
- /**
- * 获取AccessToken
- * @return
- */
- public static String obtainAccessToken(){
- String G_APPID = “公众号的APPID”;
- String G_SECRET = “公众号的SECRET”;
- String tokenData = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+G_APPID+"&secret="+G_SECRET;
- // 返回的用户信息json字符串
- JSONObject jsonObject = httpRequestUtil(tokenData);
- return String.valueOf(jsonObject.get("access_token"));
- }
-
- /**
- * 获取订阅用户的openid和unionid
- * @param accessToken
- * @param openId
- * @return
- */
- public static OpenUnionIdRelationDO obtainUserDetail(String accessToken,String openId){
- String openInfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+accessToken+"&openid="+openId+"&lang=zh_CN";
- JSONObject userDetail = httpRequestUtil(openInfoUrl);
- String openid = userDetail.getString("openid");
- Integer subscribeTime = userDetail.getInteger("subscribe_time");
- String unionid = userDetail.getString("unionid");
-
- OpenUnionIdRelationDO openDO = new OpenUnionIdRelationDO();
- openDO.setOpenId(openid);
- openDO.setUnionId(unionid);
- // 时间类型转换 10位时间戳转 yyyy-MM-dd HH:mm:ss
- String st = "";
- if (null != subscribeTime){
- st = DateUtils.timestampToString(subscribeTime);
- }
- openDO.setSubscribeTime(st);
- openDO.setCreateTime(new Date());
- return openDO;
- }

给用户推送信息
前面已经维护好了用户的公众号ID和公众号小程序的一致的unionid,小程序就可以通过unionid查询数据库中的openid给公众号用户推送信息了
- /**
- * 给关注该公众好的用户发送信息
- * @throws Exception
- */
- public static void sendTemplateInfo() throws Exception{
-
- //获取小程序accessToken
- String accessToken = obtainAccessToken();
- //消息推送接口
- String path = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken;
-
- //封装参数
- JSONObject jsonData = new JSONObject();
- jsonData.put("touser", "公众号openid");
- jsonData.put("template_id", "公众号消息模板id");
- JSONObject miniprogram = new JSONObject();
- miniprogram.put("appid","小程序ID");
- miniprogram.put("pagepath","小程序调转路径");
- jsonData.put("miniprogram",miniprogram);
-
- JSONObject data = new JSONObject();
-
- JSONObject first = new JSONObject();
- first.put("value","测试购票支付详情!");
- first.put("color","#173177");
-
- JSONObject keyword1 = new JSONObject();
- keyword1.put("value","2112323832748239");
- keyword1.put("color","#173177");
-
- JSONObject keyword2 = new JSONObject();
- keyword2.put("value","2022-12-22 00:00:00");
- keyword2.put("color","#173177");
-
- JSONObject keyword3 = new JSONObject();
- keyword3.put("value","199.56元");
- keyword3.put("color","#173177");
-
- JSONObject keyword4 = new JSONObject();
- keyword4.put("value","微信支付");
- keyword4.put("color","#173177");
-
- JSONObject remark = new JSONObject();
- remark.put("value","温馨提示:请不要爽约哦!");
- remark.put("color","#173177");
-
- data.put("first",first);
- data.put("keyword1",keyword1);
- data.put("keyword2",keyword2);
- data.put("keyword3",keyword3);
- data.put("keyword4",keyword4);
- data.put("remark",remark);
- jsonData.put("data",data);
- HttpUtil.post(path, jsonData.toJSONString());
- }

效果展示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。