快速接入微信小程序的訂閱消息


快速接入微信小程序的訂閱消息

官方文檔:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.html

2020年11月17日15:59:14  以下內容如有變更,請以官方文檔為准。

 

小程序訂閱消息

消息能力是小程序能力中的重要組成,我們為開發者提供了訂閱消息能力,以便實現服務的閉環和更優的體驗。

訂閱消息推送位置:服務通知

訂閱消息下發條件:用戶自主訂閱

訂閱消息卡片跳轉能力:點擊查看詳情可跳轉至該小程序的頁面

intro

訂閱消息包括兩種:

一次性訂閱消息

一次性訂閱消息用於解決用戶使用小程序后,后續服務環節的通知問題。用戶自主訂閱后,開發者可不限時間地下發一條對應的服務消息;每條消息可單獨訂閱或退訂。

長期訂閱消息

一次性訂閱消息可滿足小程序的大部分服務場景需求,但線下公共服務領域存在一次性訂閱無法滿足的場景,如航班延誤,需根據航班實時動態來多次發送消息提醒。為便於服務,我們提供了長期性訂閱消息,用戶訂閱一次后,開發者可長期下發多條消息。

目前長期性訂閱消息僅向政務民生、醫療、交通、金融、教育等線下公共服務開放,后期將逐步支持到其他線下公共服務業務。

 

使用說明

步驟一:獲取模板 ID

在微信公眾平台手動配置獲取模板 ID:

登錄 https://mp.weixin.qq.com 獲取模板,如果沒有合適的模板,可以申請添加新模板,審核通過后可使用。

步驟二:獲取下發權限

詳見小程序端消息訂閱接口 wx.requestSubscribeMessage

步驟三:調用接口下發訂閱消息

詳見服務端消息發送接口 subscribeMessage.send

注意事項

用戶勾選 “總是保持以上選擇,不再詢問” 之后,下次訂閱調用 wx.requestSubscribeMessage 不會彈窗,保持之前的選擇,修改選擇需要打開小程序設置進行修改。

 

快速接入

請先按照官文文檔寫的步驟開通好訂閱消息模板。

1、小程序代碼

 <!--index.wxml-->

<view class="container">
  <text class="user-motto">{{openId}}</text>
  <button class="btn green" bindtap="onSubscribe" hover-class="btn-hover">
  訂閱
  </button>
</view>

  

//index.js
//獲取應用實例
const app = getApp()

Page({
  data: {
    openId: '',
    userInfo: {},
    hasUserInfo: false,
    canIUse: wx.canIUse('button.open-type.getUserInfo')
  },
  //事件處理函數
  bindViewTap: function() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },
  //訂閱按鈕事件
  onSubscribe: function(e) {
    let that = this 
    //申請訂閱消息 模板IDXXX
    wx.requestSubscribeMessage({
      tmplIds: ['模板IDXXX'],
      success(res) {
        let status = res['模板IDXXX']
        if(status === "reject"){
          console.log("拒絕")
          //提示: 您拒絕了消息提示,后續將接收不到消息通知,打開小程序設置進行修改。
        }
        console.log(that.openId)
        //發送測試消息
        wx.request({
          url: 'http://localhost:8080/api/wxmini/sendSubscribeMessage',
          data: {
            openId: that.data.openId
          },
          success(res){
            console.log(res.data)
          }
        })
      }});
  },
  onLoad: function () {
      let that =this
      //獲取微信登錄openId
      wx.login({
        success (res) {
          //console.log(res.code)
          if (res.code) {
            //發起網絡請求
            wx.request({
              url: 'http://localhost:8080/api/wxmini/jscode2session',
              data: {
                code: res.code
              },
              success(res){
                console.log(res.data.openId)
                that.setData({
                  openId: res.data.openId
                })
              }
            })
          } else {
            console.log('登錄失敗!' + res.errMsg)
          }
        }
      })
  }
})

  

2、后台接口核心代碼
package com.zhaojie.wechat.demo.controller;

import com.zhaojie.wechat.demo.service.IWxService;
import com.zhaojie.wechat.demo.vo.Jscode2sessionVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Api(tags = {"微信小程序"})
@Slf4j
@Validated
@RestController
@RequestMapping("/api/wxmini")
public class WxMiniController {

    @Autowired
private IWxService wxService; 

@ApiOperation(value = "獲取小程序用戶的openid")
    @GetMapping("/jscode2session")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "wx.login返回的code", required = true, dataType = "String")
    })
    public Object jscode2session(@RequestParam String code) {
        Jscode2sessionVo jscode2sessionVo = wxService.jscode2session(code);
        return jscode2sessionVo;
}

    @ApiOperation(value = "小程序訂閱消息發送")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "openId", value = "接收者(用戶)的 openid", required = true, dataType = "String")
    })
    @GetMapping("/sendSubscribeMessage")
    public Object sendSubscribeMessage(@RequestParam String openId) {
        return "小程序訂閱消息" + wxService.sendSubscribeMessage(openId);
}
}

 

package com.zhaojie.wechat.demo.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zhaojie.wechat.demo.common.Constant;
import com.zhaojie.wechat.demo.service.IWxService;
import com.zhaojie.wechat.demo.vo.Jscode2sessionVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Slf4j
@Service
public class WxServiceImpl implements IWxService {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public Jscode2sessionVo jscode2session(String code) {
        //登錄憑證校驗。通過 wx.login 接口獲得臨時登錄憑證 code 后傳到開發者服務器調用此接口完成登錄流程。
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + Constant.WX_APP_ID +
                "&secret=" + Constant.WX_SECRET + "&js_code=" + code + "&grant_type=authorization_code";
        String forObject = restTemplate.getForObject(url, String.class);
        //返回的 JSON 數據包
        //屬性   類型 說明
        //openid   string 用戶唯一標識
        //session_key  string 會話密鑰
        //unionid  string 用戶在開放平台的唯一標識符,在滿足 UnionID 下發條件的情況下會返回,詳見 UnionID 機制說明。
        //errcode  number 錯誤碼
        //errmsg   string 錯誤信息
        JSONObject result = JSONUtil.parseObj(forObject);
        Jscode2sessionVo jscode2sessionVo = new Jscode2sessionVo();
        jscode2sessionVo.setOpenId(result.getStr("openid"));
        jscode2sessionVo.setErrmsg(result.getStr("errmsg"));
        jscode2sessionVo.setErrcode(result.getStr("errcode"));
        return jscode2sessionVo;
    }

    @Override
    public String getAccessToken() {
        try {
            // 線上不需要每次都去獲取access_token,需要把它緩存起來。我這里僅測試就不緩存了!!!
            /*String redisAccessToken = redisSeConstantrvice.get(Constant.WX_ACCESS_TOKEN);
            if (StrUtil.isNotEmpty(redisAccessToken)) {
                return redisAccessToken;
            }*/
            //獲取小程序全局唯一后台接口調用憑據(access_token)。調用絕大多數后台接口時都需使用 access_token,開發者需要進行妥善保存。
            String url = "https://api.weixin.qq.com/cgi-bin/token?appid=" + Constant.WX_APP_ID +
                    "&secret=" + Constant.WX_SECRET + "&grant_type=client_credential";
            String forObject = restTemplate.getForObject(url, String.class);
            //返回的 JSON 數據包
            //屬性   類型 說明
            //access_token string 獲取到的憑證
            //expires_in   number 憑證有效時間,單位:秒。目前是7200秒之內的值。
            //errcode  number 錯誤碼
            //errmsg   string 錯誤信息
            log.error("獲取小程序全局唯一后台接口調用憑據,msg{}", forObject);
            JSONObject result = JSONUtil.parseObj(forObject);
            String accessToken = result.getStr("access_token");
            /*if (StrUtil.isNotEmpty(accessToken)) {
                //存入Redis
                redisService.set(Constant.WX_ACCESS_TOKEN, accessToken, 7200 * 1000L);
            }*/
            return accessToken;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String sendSubscribeMessage(String openId) {
        String accessToken = this.getAccessToken();
        log.info("accessToken {}", accessToken);
        HttpHeaders httpHeaders = new HttpHeaders();
        //注意這里要是json格式的提交
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        //我這里測試直接拼接的,請按照你自己模板的配置去改下面的json字符串
        //官方文檔:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
        StringBuffer jsonParam = new StringBuffer();
        jsonParam.append("{");
        jsonParam.append("\"touser\": \"" + openId + "\",");
        jsonParam.append("\"template_id\": \"" + Constant.WX_TMPL_ID + "\",");
        jsonParam.append("\"page\": \"" + Constant.WX_TMPL_PAGE + "\",");
        jsonParam.append("\"data\": {");
        jsonParam.append("\"name1\": { \"value\": \"zhaojie\"},");
        jsonParam.append("\"thing13\": { \"value\": \"預約產品\"},");
        jsonParam.append("\"date3\": { \"value\": \"2020年11月17日 16:59\"},");
        jsonParam.append("\"phrase9\": { \"value\": \"預約中\"},");
        jsonParam.append("\"thing7\": { \"value\": \"如有疑問請聯系客服人員\"}");
        jsonParam.append("}");
        jsonParam.append("}");
        HttpEntity<String> httpEntity = new HttpEntity<>(jsonParam.toString(), httpHeaders);
        ResponseEntity<String> entity = restTemplate.exchange("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken,
                HttpMethod.POST, httpEntity, String.class);
        String result = entity.getBody();
        log.info("result {}", result);
        return result;
    }
}

  

package com.zhaojie.wechat.demo.common;

/**
 * 常量
 */
public class Constant {
    // 系統前綴
    public static final String SYS_PREFIX = "WECHAT-DEMO:";
    // 小程序全局唯一后台接口調用憑據(access_token)。調用絕大多數后台接口時都需使用 access_token,開發者需要進行妥善保存。
    public static final String WX_ACCESS_TOKEN = SYS_PREFIX + "WX_ACCESS_TOKEN";
    // 小程序訂閱消息模板 改成自己的參數
    public static final String WX_TMPL_ID = "XXXXX;
    public static final String WX_TMPL_PAGE = "pages/index/index";
    // 小程序配置信息 改成自己的
    public static final String WX_APP_ID = "XXXX";
    public static final String WX_SECRET = "XXXX";
}

  

 

 

3、運行結果

注意未發布體驗版無法接收到消息

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM