天天看點

微信小程式---訂閱消息1,登入微信公衆平台擷取訂閱資訊的模闆id2,擷取下發權限

在做退款的時候需要給使用者發一條消息,告訴他已經在退款了,一開始是想用模闆消息來做的,但是看微信開發文檔說模闆消息要下線,推薦用訂閱資訊。這邊記錄一些步驟。

1,登入微信公衆平台擷取訂閱資訊的模闆id

登入微信公衆平台,點選訂閱資訊,我的模闆,添加我的模闆,微信會提供一些常用的模闆,可以選擇,也可以自己申請,通過就可以使用了,把模闆id複制下來儲存一下。代碼裡面需要用到。

微信小程式---訂閱消息1,登入微信公衆平台擷取訂閱資訊的模闆id2,擷取下發權限

2,擷取下發權限

看微信開發文檔用的是這個接口: wx.requestSubscribeMessage ,詳細資訊可以自己檢視微信開發文檔

https://developers.weixin.qq.com/miniprogram/dev/api/open-api/subscribe-message/wx.requestSubscribeMessage.html

下面簡單的看一下代碼的實作:

index.wxml 代碼

<button  class="v-btn mt40" bindtap="sendMsg">發送訂閱消息</button>
  
           

index.js 代碼 ,簡單介紹一下,tmplIds 參數是在微信公衆平台申請的訂閱資訊模闆id,wx.requestSubscribeMessage 方法是判斷使用者是否授權發訂閱模闆的資訊,同意了就發http請求,請求背景的接口,然後可能是為了安全考慮這個請求的位址必須是https 請求,這個問題可以在微信開發工具裡面設定一下,設定他不要驗證域名;

步驟是,打開微信開發工具--設定--項目設定 ,這個就可以不要驗證域名,真實環境肯定是不推薦這麼做的,但是這樣調試友善。

微信小程式---訂閱消息1,登入微信公衆平台擷取訂閱資訊的模闆id2,擷取下發權限
sendMsg: function (e) {
    wx.requestSubscribeMessage({
      tmplIds: ["0a-wSlLk6TGc9f8qsar9XtF65qtDh5XiSIhmSGSDrn0"],
      success: function (res) {
        //成功
        console.log(res)
        if (res['0a-wSlLk6TGc9f8qsar9XtF65qtDh5XiSIhmSGSDrn0'] === 'accept'){
          console.log("使用者同意授權了")
          wx.login({
            success(res) {
              console.log(res.code)
             
              wx.request({
                url: 'http://3s.dkys.org:25451/farina-api/subscription/subscription',
                method: 'POST',
                data: { 
                  code : res.code,
                  price : 1001,
                  url : "index.html",
                
                },
                header: {
                  'content-type': 'application/x-www-form-urlencoded', // POST請求
                  'token': "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHQiOjE1NzU2MDM5NTY5MjcsInVpZCI6IjE4MTI3MDg0ODIiLCJzcmMiOiJBUFAiLCJpYXQiOjE1NzU1OTYxODA5Mjd9.fW_U_MQtovt7d5Nzl7HR1i9pe_y62oTO7gmVU4FrgO4",
                },
                success(res) {
                  console.log(res)
                }
              })
              
            }
          })


        
        }else{
          console.log("使用者拒絕了======================")
        }

     
      },
      fail(err) {
        //失敗
        console.log("這個是失敗的哦=========");
        console.error(err);
      }
    })
  }
           

price,是退款金額,URL,是訂閱資訊傳回使用者點選的回跳頁面,code,就不要介紹了吧,請求頭,content-type ,正常請求頭,token,我們項目的key,

3.調用接口下發訂閱消息

拉下發訂閱資訊接口的代碼我是寫在了後端,

工具包類

package io.farina.MessageSubscription;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;


public class HttpUtil {

private static final CloseableHttpClient httpclient = HttpClients.createDefault();

/**
 * 發送HttpGet請求
 * @param url
 * @return
 */
public static String sendGet(String url) {

    HttpGet httpget = new HttpGet(url);
    CloseableHttpResponse response = null;
    try {
        response = httpclient.execute(httpget);
    } catch (IOException e1) {
        e1.printStackTrace();
    }
    String result = null;
    try {
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            result = EntityUtils.toString(entity);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            response.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return result;
}

/**
 * 發送HttpPost請求,參數為map
 * @param url
 * @param map
 * @return
 */
public static String sendPost(String url, Map<String, String> map) {
    List<NameValuePair> formparams = new ArrayList<NameValuePair>();
    for (Map.Entry<String, String> entry : map.entrySet()) {
        formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
    }
    UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
    HttpPost httppost = new HttpPost(url);
    httppost.setEntity(entity);
    CloseableHttpResponse response = null;
    try {
        response = httpclient.execute(httppost);
    } catch (IOException e) {
        e.printStackTrace();
    }
    HttpEntity entity1 = response.getEntity();
    String result = null;
    try {
        result = EntityUtils.toString(entity1);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return result;
}

/**
 * 發送不帶參數的HttpPost請求
 * @param url
 * @return
 */
public static String sendPost(String url) {
    HttpPost httppost = new HttpPost(url);
    CloseableHttpResponse response = null;
    try {
        response = httpclient.execute(httppost);
    } catch (IOException e) {
        e.printStackTrace();
    }
    HttpEntity entity = response.getEntity();
    String result = null;
    try {
        result = EntityUtils.toString(entity);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return result;
}
/**
 * 向指定 URL 發送POST方法的請求
 * 
 * @param url
 *            發送請求的 URL
 * @param string
 *            請求參數,請求參數應該是 name1=value1&name2=value2 的形式。
 * @return 所代表遠端資源的響應結果
 */
public static String sendPost(String url, String string) {
    PrintWriter out = null;
    BufferedReader in = null;
    String result = "";
    try {
        URL realUrl = new URL(url);
        // 打開和URL之間的連接配接
        URLConnection conn = realUrl.openConnection();
        // 設定通用的請求屬性
        conn.setRequestProperty("accept", "*/*");
        conn.setRequestProperty("connection", "Keep-Alive");
        conn.setRequestProperty("user-agent",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        // 發送POST請求必須設定如下兩行
        conn.setDoOutput(true);
        conn.setDoInput(true);
        // 擷取URLConnection對象對應的輸出流
        out = new PrintWriter(conn.getOutputStream());
        // 發送請求參數
        out.print(string);
        // flush輸出流的緩沖
        out.flush();
        // 定義BufferedReader輸入流來讀取URL的響應
        in = new BufferedReader(
                new InputStreamReader(conn.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            result += line;
        }
    } catch (Exception e) {
        System.out.println("發送 POST 請求出現異常!"+e);
        e.printStackTrace();
    }
    //使用finally塊來關閉輸出流、輸入流
    finally{
        try{
            if(out!=null){
                out.close();
            }
            if(in!=null){
                in.close();
            }
        }
        catch(IOException ex){
            ex.printStackTrace();
        }
    }
    return result;
}  



}
           
package io.farina.MessageSubscription;

public class TemplateParam {
	

		private String key;  
		private String value;  

		public TemplateParam(String key,String value){  
		    this.key=key;  
		    this.value=value;  
		}  
		public String getValue() {  
		    return value;  
		}  
		public void setValue(String value) {  
		    this.value = value;  
		}
		public String getKey() {
			return key;
		}
		public void setKey(String key) {
			this.key = key;
		}  


}
           
package io.farina.MessageSubscription;

import java.util.List;

public class Template {
	
	private String touser;  
	private String template_id;  
	private String page;
	private List<TemplateParam> templateParamList;
	public String getTouser() {
		return touser;
	}
	public void setTouser(String touser) {
		this.touser = touser;
	}
	public String getTemplate_id() {
		return template_id;
	}
	public void setTemplate_id(String template_id) {
		this.template_id = template_id;
	}
	public String getPage() {
		return page;
	}
	public void setPage(String page) {
		this.page = page;
	}
	public List<TemplateParam> getTemplateParamList() {
		return templateParamList;
	}
	public void setTemplateParamList(List<TemplateParam> templateParamList) {
		this.templateParamList = templateParamList;
	}    
	public String toJSON() {  
	    StringBuffer buffer = new StringBuffer();  
	    buffer.append("{");  
	    buffer.append(String.format("\"touser\":\"%s\"", this.touser)).append(",");  
	    buffer.append(String.format("\"template_id\":\"%s\"", this.template_id)).append(",");  
	    buffer.append(String.format("\"page\":\"%s\"", this.page)).append(","); 
	    buffer.append("\"data\":{");  
	    TemplateParam param = null;  
	    for (int i = 0; i < this.templateParamList.size(); i++) {  
	         param = templateParamList.get(i);  
	        // 判斷是否追加逗号  
	        if (i < this.templateParamList.size() - 1){  
	            buffer.append(String.format("\"%s\": {\"value\":\"%s\"},", param.getKey(), param.getValue()));  
	        }else{  
	            buffer.append(String.format("\"%s\": {\"value\":\"%s\"}", param.getKey(), param.getValue()));  
	        }  
	    }  
	    buffer.append("}");  
	    buffer.append("}");  
	    return buffer.toString();  
	    } 

	
	
	

}
           
package io.farina.MessageSubscription;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;
/**
 * 實作了 MyX509TrustManager 接口
 * @author admin
 *
 */
public class MyX509TrustManager implements X509TrustManager  {
	

	 
	// 檢查用戶端證書
	public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	}
 
	// 檢查伺服器端證書
	public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	}
 
	// 傳回受信任的X509證書數組
	public X509Certificate[] getAcceptedIssuers() {
		return null;
	}



}
           

下發訂閱資訊接口

package io.farina.MessageSubscription;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;


/****
 * 退款提示
 * @author admin
 *
 */
@RestController
@RequestMapping("subscription")
public class MessageSubscriptionController2 {
	protected final Logger log = LoggerFactory.getLogger(this.getClass());
	

	
	/***
	 * 擷取ACCESS_TOKEN
	 * @return
	 */
	public String  subscroption() {
		String appid="微信小程式appid";
		String secret="微信小程式secret";
		String url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
				+ appid+ "&secret="+ secret;
		String results = HttpUtil.sendGet(url);
		JSONObject jsonObject =JSONObject.parseObject(results);
		String Access_Token=jsonObject.get("access_token").toString();
		return Access_Token;
	
	}
	
	/****
	 * 擷取opneid和sessionKey
	 * 
	 * @param code
	 * @return
	 * @throws Exception 
	 */
	public JSONObject getSessionKeyOrOpenId(String code) throws Exception {

			// 微信端登入code
			String wxCode = code;
			// 請求路徑
			String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";
			String appid="小程式appid";
			String secret="小程式secret";

			//b2d42c4f39cf71f60416546cdb2855e1
			String requestUrlParam = "appid="+appid+"&secret="+secret+"&js_code=" + wxCode
					+ "&grant_type=authorization_code";
			// Java發post請求
			//HttpUtil.sendPost(url, map);
			
			JSONObject jsonObject = JSON.parseObject(HttpUtil.sendPost(requestUrl, requestUrlParam));
			if (jsonObject.get("errcode")!=null) {
				 //logger.error("code擷取oppid和sessionkey 異常,檢查小程式配置是否正确");
				 throw new Exception("異常資訊:"+jsonObject.get("errmsg").toString());
			}
			return jsonObject;
	}
	

	/****
	 * 退款資訊訂閱
	 * @param price 提款金額
	 * @param url 小程式倉庫的位址
	 * @param code  code
	 */
	@RequestMapping(value = "/subscription", method = RequestMethod.POST)
	public void sund(
			@RequestParam(value = "price", required = false) String price,
			@RequestParam(value = "url", required = true) String url,
			@RequestParam(value = "code", required = true) String code) {
		log.info("請求提款接口參數,提款金額:[{}],傳回位址:[{}],code:[{}]",price,url,code);
		//擷取openid
		Map<String, Object> map = new HashMap<String, Object>();
		com.alibaba.fastjson.JSONObject SessionKeyOpenId;
		String openid="";
		try {
			SessionKeyOpenId =getSessionKeyOrOpenId(code);
			openid = SessionKeyOpenId.getString("openid");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		String access_Token=subscroption();
		Template template=new Template();  
		//訂閱消息 子產品id,
		template.setTemplate_id("訂閱資訊模闆id"); 
		//openId
		template.setTouser(openid);
		//這個是訂閱資訊點進去的時候進去的界面,
		template.setPage(url);
		List<TemplateParam> paras=new ArrayList<TemplateParam>();  
		//這些參數在/訂閱資訊/詳情/詳細資訊裡面找 ,把後面的  {{thing5.DATA}} 取 thing5
		paras.add(new TemplateParam("thing5","預計1~5工作日到微信錢包,請注意查收"));  
		paras.add(new TemplateParam("amount1",price));  
		paras.add(new TemplateParam("thing4","提款到微信錢包"));  
		template.setTemplateParamList(paras); 
		//給訂閱的使用者發資訊的位址
	    String requestUrl="https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN";  
	    //替換 ACCESS_TOKEN
	    requestUrl=requestUrl.replace("ACCESS_TOKEN", access_Token); 
		//使用者授權後給使用者發訂閱的資訊,使用者授權在前端處理
	    JSONObject jsonResult=httpsRequest(requestUrl, "POST", template.toJSON());  
	    int newcode=Integer.parseInt(jsonResult.get("errcode").toString());
	    if (jsonResult.get("errmsg").equals("ok")&&newcode==0) {
	    	log.info("訂閱資訊發送成功====");
	    	
		}	
	    log.info("訂閱資訊發送失敗====");
	   
	}
	

	public  JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {   
	    JSONObject jsonObject = null;  
	    StringBuffer buffer = new StringBuffer();    
	    try {    
	        // 建立SSLContext對象,并使用我們指定的信任管理器初始化    
	        TrustManager[] tm = { new MyX509TrustManager() };    
	        SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");    
	        sslContext.init(null, tm, new java.security.SecureRandom());    
	        // 從上述SSLContext對象中得到SSLSocketFactory對象    
	        SSLSocketFactory ssf = sslContext.getSocketFactory();    
	        URL url = new URL(requestUrl);    
	        HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();    
	        httpUrlConn.setSSLSocketFactory(ssf);    
	        httpUrlConn.setDoOutput(true);    
	        httpUrlConn.setDoInput(true);    
	        httpUrlConn.setUseCaches(false);    
	        // 設定請求方式(GET/POST)    
	        httpUrlConn.setRequestMethod(requestMethod);    

	        if ("GET".equalsIgnoreCase(requestMethod)) {  
	             httpUrlConn.connect();    
	        }   
	        // 當有資料需要送出時    
	        if (null != outputStr) {    
	            OutputStream outputStream = httpUrlConn.getOutputStream();    
	            // 注意編碼格式,防止中文亂碼    
	            outputStream.write(outputStr.getBytes("UTF-8"));    
	            outputStream.close();    
	        }    
	        // 将傳回的輸入流轉換成字元串    
	        InputStream inputStream = httpUrlConn.getInputStream();    
	        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");    
	        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);    
	        String str = null;    
	        while ((str = bufferedReader.readLine()) != null) {    
	            buffer.append(str);    
	        }    
	        bufferedReader.close();    
	        inputStreamReader.close();    
	        // 釋放資源    
	        inputStream.close();    
	        inputStream = null;    
	        httpUrlConn.disconnect(); 
	        jsonObject= JSONObject.parseObject(buffer.toString());
	    } catch (ConnectException ce) {    
	        ce.printStackTrace();  
	    } catch (Exception e) {    
	        e.printStackTrace();  
	    }    
	    return jsonObject;    
	}

}
           

ok,代碼大概就是這個樣子