一文搞定微信接入自定义消息推送

967 阅读2分钟

我正在参加「掘金·启航计划」

首先上的是微信官方文档:developers.weixin.qq.com/minigame/de…

由于微信支付具有一定的限制性,所以我们在特定的场景下,用户可以跳转到公众号,然后发送对应的url后拉起支付。那么这种场景是怎么实现的呢。就是通过消息推送实现的。 我们可以看下下面的一个使用场景,小程序无法支付的情况下,用户跳转到微信公众号完成付费。

image.png

  • url:服务的地址一般服务器地址+接口名称
  • token令牌+消息加密秘钥:可以自定义
  • 消息加密方式+数据格式:建议明文+XML方面

回调测试代码,主要是为了让微信服务器调用。能够将正确的报文返回给微信。

@RequestMapping(value = "/checkWeixinValid", method = RequestMethod.GET)
    public String checkWeixinValid(@RequestParam(name = "signature") String signature,
                                   @RequestParam(name = "timestamp") String timestamp,
                                   @RequestParam(name = "nonce") String nonce,
                                   @RequestParam(name = "echostr") String echostr) {
        // .......
        return echostr;
    }

真实案例:

  1. 本次是用了xml的方式解析。所以会有一步是将xml解析成map。
  2. 解析完成,看参数的组成,然后根据自定义的规则去过滤组装参数。
  3. 给微信发送消息。

image.png

最后附上代码(代码仅供参考,如果需要交流可以关注私信我):

	@RequestMapping(value = "/checkWeixinValid", method = RequestMethod.POST)
    public void replyMessage(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, String> map = null;
        //从工具类中获取XML解析之后的map
        try {
            map = readWechatXml(request);
        } catch (IOException e) {
            log.error("获取输入流失败", e);
        } catch (DocumentException e) {
            log.error("读取XML失败", e);
        }
        assert map != null;
        replyMessage(map,response);
        log.info("自动回复的消息内容为:{}", JSON.toJSONString(map));
    }

	@SuppressWarnings("unchecked")
    public static Map<String, String> readWechatXml(HttpServletRequest request) throws IOException, DocumentException {
        Map<String, String> map = new HashMap<String, String>(16);
        //获取输入流
        InputStream input = request.getInputStream();
        //使用dom4j的SAXReader读取(org.dom4j.io.SAXReader;)
        SAXReader sax = new SAXReader();
        Document doc = sax.read(input);
        //获取XML数据包根元素
        Element root = doc.getRootElement();
        //得到根元素的所有子节点

        List<Element> elementList = root.elements();
        //遍历所有节点并将其放进map
        for (Element e : elementList) {
            map.put(e.getName(), e.getText());
        }
        //释放资源
        input.close();
        return map;
    }

	// 发送消息
	public void replyMessage(Map<String, String> msg, HttpServletResponse response) throws Exception {
        System.out.println("客服消息自动回复 ====> start");
        String opendId = msg.get("FromUserName");
        Map<String, String> contenMap = Maps.newHashMapWithExpectedSize(2);
        // 若用户消息包含关键字则自动回复

        try {
            // 给用户发送的消息
            contenMap.put("content", "请点击链接打开APP:" + "https://www.baidu.com");
        } catch (Exception e) {
            contenMap.put("content", e.getMessage());
        }
        sendMessage(opendId, "text", contenMap);
        // 此处将消息转发至人工客服,不然人工客服窗会没有消息
        Map<String, Object> tranMap = Maps.newHashMapWithExpectedSize(4);
        tranMap.put("ToUserName", msg.get("FromUserName"));
        tranMap.put("FromUserName", msg.get("ToUserName"));
        tranMap.put("CreateTime", msg.get("CreateTime"));
        tranMap.put("MsgType", "transfer_customer_service");
        printData(JSONObject.toJSONString(tranMap), response);
    }

	// 发送消息
	private void sendMessage(String opendId, String msgType, Map<String, String> contentMap) throws
        UnsupportedEncodingException {
        Map<String, Object> replyMessageMap = Maps.newHashMapWithExpectedSize(4);
        replyMessageMap.put("touser", opendId);
        replyMessageMap.put("msgtype", msgType);
        replyMessageMap.put(msgType, contentMap);
        String messageJson = JSONObject.toJSONString(replyMessageMap);
        messageJson = new String(messageJson.getBytes(), "UTF-8");
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"
            .replace("APPID", "appId")
            .replace("APPSECRET", "secret");
        String response = HttpUtil.get(url);
        if (response == null) {
            return;
        }
        WxAccessTokenRes wxAccessTokenRes = JSONUtil.toBean(response, WxAccessTokenRes.class);
        String geturl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="
            + wxAccessTokenRes.getAccess_token();
        // 发送结果
        HttpUtil.post(geturl, messageJson);
    }

	private void printData(String data, HttpServletResponse resp) {
        PrintWriter out;
        try {
            resp.reset();
            resp.getOutputStream().print("success");
            out = resp.getWriter();
            out.print(data);
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }