小程序開發與公衆號用戶關聯推送消息

最近做了一個類似於日程提醒的小程序,需要把用戶語音識別出的日程或提醒按照設置的提醒日期通過微信公衆號推送給對應的用戶進行提醒這樣子.這是需求背景.

    這個項目我已經做完了,但是中間遇到很多坑,所以想出篇帖子,讓大家不浪費爬坑的時間.後面我會盡量把所有需要的代碼什麼的,都貼上來,儘量做到拿了就能用的程度.


    接下來,就是一個又一個的坑需要爬了.首先我說一下小程序與公衆號開發的一個完整流程.與一些細節.


1.小程序開發首先需要appid 與secret  也就是賬號密碼,用來獲取用戶的unionid與openid.(需要根據js_code來獲取)這兩個名叫id的東西,都是用戶的唯一標識,(以前不同的appid獲取到的用戶openid都是一樣的,現在不一樣了) unionid是幹什麼用的,我一會會說.

2.公衆號開發也需要一個appid跟secret,這個跟小程序的不一樣,具體怎麼拿,跟小程序一樣.有了appid與secret我們就可以獲取到公衆號用戶的openid與unionid了(需要根據code來獲取),(獲取之前還需要先獲取assess_token,這是一個微信的接口,用來驗證身份,微信設置一個開發者賬號每天可以請求200次的限制,每個token有7200s的有效時間...所以這裏獲取到的話,需要放到redis或者java緩存中去,然後設置一個7200s的過期時間,用的時候從緩存取,緩存裏沒有再請求.後面我會說怎麼獲取)這裏的openid與小程序的openid是不一樣的,但是unionid可以弄成一樣的.怎麼弄呢,看第三步.

3.這時候應該上微信公衆平臺把小程序綁定到其下.然後再註冊一個微信開放平臺,並且獲取開發者資質,(一年好像是300).然後把你的小程序與公衆號都綁定到開放平臺下,這樣的話,你的小程序獲取到的unionid跟公衆號獲取到的unionid就是一樣的了,這樣就可以用它來進行小程序與公衆號用戶的關聯了.

------------------------------------------------------然後進行代碼------------------------------------------------------


1.根據js_code獲取小程序用戶的openid與unionid  (js_code 是小程序在調用wx.login的時候獲取到的.)  代碼如下:

	@RequestMapping(value = "/checkUserByOpenid", method = RequestMethod.GET)
	public @ResponseBody Map checkUserByOpenid(HttpServletRequest request,HttpServletResponse response,
			@RequestParam("js_code") String js_code) throws Exception {
		response.setHeader("Access-Control-Allow-Origin", "*");
		/*星號表示所有的域都可以接受,*/
		response.setHeader("Access-Control-Allow-Methods", "GET,POST");
		HashMap<String, Object> jsonMap = new HashMap<String, Object>();
//		if(js_code!=null && !"".equals(js_code)){
		    String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + js_code + "&grant_type=" + grant_type;
		    String httpsRtn = HttpsPostUtil.doPost(url, "UTF-8");
		    Map<String, Object> json = mapper.readValue(httpsRtn, Map.class);
		    String openid = (String) json.get("openid");
		    //用openid獲取unionid等敏感信息------------小程序
		    String unionid = (String) json.get("unionid");
	            //此處開始你的邏輯代碼
		    jsonMap.put("message", "success");
//		}
		return jsonMap;
	}

2.httpsclient工具類  發送請求給微信接口

package com.qs.util;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.util.EntityUtils;

/**
 * 利用HttpClient進行post請求的工具類
 *
 * @author Kevin
 * @ClassName: HttpsClientUtil
 * @Description: TODO
 * @date 2017年2月7日 下午1:43:38
 */
public class HttpsPostUtil {
    public static String doPost(String url, String charset) {
        HttpClient httpClient = null;
        HttpPost httpPost = null;
        String result = null;
        try {
            httpClient = new SSLClient();
            httpPost = new HttpPost(url);
            HttpResponse response = httpClient.execute(httpPost);
            if (response != null) {
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, charset);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }
}
package com.qs.util;

import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * 用於進行Https請求的HttpClient
 *
 * @author Kevin 
 * @ClassName: SSLClient
 * @Description: TODO
 * @date 2017年2月7日 下午1:42:07
 */
public class SSLClient extends DefaultHttpClient {
    public SSLClient() throws Exception {
        super();
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        ctx.init(null, new TrustManager[]{tm}, null);
        SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        ClientConnectionManager ccm = this.getConnectionManager();
        SchemeRegistry sr = ccm.getSchemeRegistry();
        sr.register(new Scheme("https", 443, ssf));
    }
}

3.然後再根據code獲取公衆號下用戶的openid與uninonid等個人信息了,這裏要多說一下,這個code在小程序裏面是無法直接獲取的,我是在小程序wx.login後調用了web view網頁彈出  來引導用戶進行授權的,這裏大家可以參考一下微信的官方說明文檔,需要配置一個服務器域名  或  測試用機的IP地址白名單,還要配置一個授權成功後回調的接口地址,也就是你自己寫的接口,這個接口中就可以獲取到code,code是從你的授權網頁傳遞過來的,在網頁上寫一個onload默認加載,把頁面地址欄裏接收到的微信傳來的code參數拿出來,傳到自己的接口中去..下面我把接口中根據code獲取微信公衆平臺用戶的個人信息代碼貼上

	@RequestMapping(value = "/callBack", method = RequestMethod.GET)
	public @ResponseBody void callBack(HttpServletRequest request,HttpServletResponse response) throws Exception {
		response.setHeader("Access-Control-Allow-Origin", "*");
		/*星號表示所有的域都可以接受,*/
		response.setHeader("Access-Control-Allow-Methods", "GET,POST");
	       //使用code獲取公衆號用戶的openid------------
        String urls = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appId+"&secret="+appSecret+"&code="+code+"&grant_type=authorization_code";
        JSONObject result = WX_HttpsUtil.httpsRequest(urls, "GET");
        JSONObject resultJson = new JSONObject(result);
        String GZHopenid = (String) resultJson.get("openid");
        String errmsg = (String) resultJson.get("errmsg");
        //如果code失效  則不添加用戶
        if(errmsg==null){
	        //使用openid獲取unionid
	        String access_token = WX_TokenUtil.getWXToken().getAccessToken();
	        String url2 = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+access_token+"&openid="+GZHopenid+"&lang=zh_CN";
	        JSONObject result2 = WX_HttpsUtil.httpsRequest(url2, "GET");
	        JSONObject resultJson2 = new JSONObject(result2);
	        String GZHunionid = (String) resultJson.get("unionid");
        }
		
	}



---------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------

到這裏爲止,你的公衆號與小程序的用戶的個人信息就全部獲取到了,可以通過unionid關聯起來了...



下面開始通過微信公衆平臺來給用戶推送消息.

ps:這裏需要登錄微信公衆平臺先設置一個自己需要推送的消息模板,可以從微信提供的模板庫中選取,如果沒有合適的,就自己申請一個模板,然後把模板ID複製粘貼到代碼中.

如下幾個都是需要的工具類 

package weixin.util.wxservlet;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
 * 請求校驗工具類
 * @author m
 *
 */
public class SignUtil {
    // 與接口配置信息中的Token要一致  
    private static String token = "weixin";  

    /** 
     * 驗證簽名 
     *  
     * @param signature 
     * @param timestamp 
     * @param nonce 
     * @return 
     */  
    public static boolean checkSignature(String signature, String timestamp, String nonce) {  
        String[] arr = new String[] { token, timestamp, nonce };  
        // 將token、timestamp、nonce三個參數進行字典序排序  
        Arrays.sort(arr);  
        StringBuilder content = new StringBuilder();  
        for (int i = 0; i < arr.length; i++) {  
            content.append(arr[i]);  
        }  
        MessageDigest md = null;  
        String tmpStr = null;  

        try {  
            md = MessageDigest.getInstance("SHA-1");  
            // 將三個參數字符串拼接成一個字符串進行sha1加密  
            byte[] digest = md.digest(content.toString().getBytes());  
            tmpStr = byteToStr(digest);  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
        }  

        content = null;  
        // 將sha1加密後的字符串可與signature對比,標識該請求來源於微信  
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;  
    }  

    /** 
     * 將字節數組轉換爲十六進制字符串 
     *  
     * @param byteArray 
     * @return 
     */  
    private static String byteToStr(byte[] byteArray) {  
        String strDigest = "";  
        for (int i = 0; i < byteArray.length; i++) {  
            strDigest += byteToHexStr(byteArray[i]);  
        }  
        return strDigest;  
    }  

    /** 
     * 將字節轉換爲十六進制字符串 
     *  
     * @param mByte 
     * @return 
     */  
    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;  
    }  
}
package weixin.util.wxservlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class WxServlet extends HttpServlet{

    public WxServlet() {
        // TODO Auto-generated constructor stub
    }

    /* (non-Javadoc)
     * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 微信加密簽名  
        String signature = request.getParameter("signature");  
        // 時間戳  
        String timestamp = request.getParameter("timestamp");  
        // 隨機數  
        String nonce = request.getParameter("nonce");  
        // 隨機字符串  
        String echostr = request.getParameter("echostr");  

        PrintWriter out = response.getWriter();  
        // 通過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗  
        if (SignUtil.checkSignature(signature, timestamp, nonce)) {  
            out.print(echostr);  
        }  
        out.close();  
        out = null;  
    }

    /* (non-Javadoc)
     * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // TODO Auto-generated method stub
        super.doPost(req, resp);
    }

}

package weixin.util;

import java.io.Serializable;
/*
*AccessToken 對象
*/
public class AccessToken implements Serializable {
    //獲取到的憑證
    private String accessToken;
    //憑證有效時間,單位:秒
    private int expiresin;  
    /**
     * @return the accessToken
     */
    public String getAccessToken() {
        return accessToken;
    }
    /**
     * @param accessToken the accessToken to set
     */
    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }
    /**
     * @return the expiresin
     */
    public int getExpiresin() {
        return expiresin;
    }
    /**
     * @param expiresin the expiresin to set
     */
    public void setExpiresin(int expiresin) {
        this.expiresin = expiresin;
    }
    public AccessToken() {
        // TODO Auto-generated constructor stub
    }

}
package weixin.util;

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

import javax.net.ssl.X509TrustManager;
/**
 * 微信請求 - 信任管理器
 */

public class MyX509TrustManager implements X509TrustManager{

    public MyX509TrustManager() {
        // TODO Auto-generated constructor stub
    }
      public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }
        public X509Certificate[] getAcceptedIssuers() {
        //        return new X509Certificate[0];
            return  null;
        }

}

package weixin.util;
/**
 * 模板詳細信息 
 * 根據需求自己更改
 */
public class TemplateData {
    private String value;
    private String color;
    public TemplateData(String value,String color){
        this.value = value;
        this.color = color;
    }
    /**
     * @return the value
     */
    public String getValue() {
        return value;
    }
    /**
     * @param value the value to set
     */
    public void setValue(String value) {
        this.value = value;
    }
    /**
     * @return the color
     */
    public String getColor() {
        return color;
    }
    /**
     * @param color the color to set
     */
    public void setColor(String color) {
        this.color = color;
    }

}

package weixin.util;

import java.util.Map;

/**
 * 註冊成功,通知模板消息實體類
 */
public class TemplateMessage {
    private String touser; //用戶OpenID
    private String template_id; //模板消息ID
    private String url; //URL置空,在發送後,點模板消息進入一個空白頁面(ios),或無法點擊(android)。
    private String topcolor; //標題顏色
    private Map<String, TemplateData> templateData; //模板詳細信息

    public static TemplateMessage New() {
        return new TemplateMessage();
    }

    /**
     * @return the touser
     */
    public String getTouser() {
        return touser;
    }
    /**
     * @param touser the touser to set
     */
    public void setTouser(String touser) {
        this.touser = touser;
    }
    /**
     * @return the template_id
     */
    public String getTemplate_id() {
        return template_id;
    }
    /**
     * @param template_id the template_id to set
     */
    public void setTemplate_id(String template_id) {
        this.template_id = template_id;
    }
    /**
     * @return the url
     */
    public String getUrl() {
        return url;
    }
    /**
     * @param url the url to set
     */
    public void setUrl(String url) {
        this.url = url;
    }
    /**
     * @return the topcolor
     */
    public String getTopcolor() {
        return topcolor;
    }
    /**
     * @param topcolor the topcolor to set
     */
    public void setTopcolor(String topcolor) {
        this.topcolor = topcolor;
    }
    /**
     * @return the templateData
     */
    public Map<String, TemplateData> getTemplateData() {
        return templateData;
    }
    /**
     * @param templateData the templateData to set
     */
    public void setTemplateData(Map<String, TemplateData> templateData) {
        this.templateData = templateData;
    }



}
package weixin.util;

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 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 com.alibaba.fastjson.JSONObject;

public class WX_HttpsUtil {

    private static Logger log = LoggerFactory.getLogger(WX_HttpsUtil.class);
    /**
     * 發送https請求
     * @param requestUrl 請求地址
     * @param requestMethod 請求方式(GET、POST)
     * @param outputStr 提交的數據
     * @return JSONObject(通過JSONObject.get(key)的方式獲取json對象的屬性值)
     */
    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        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 conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 設置請求方式(GET/POST)
            conn.setRequestMethod(requestMethod);
            // 當outputStr不爲null時向輸出流寫數據
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意編碼格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 從輸入流讀取返回內容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 釋放資源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            jsonObject = JSONObject.parseObject(buffer.toString());
        } catch (ConnectException ce) {
            log.error("連接超時:{}", ce);
        } catch (Exception e) {
            log.error("https請求異常:{}", e);
        }
        return jsonObject;
    }

}

package weixin.util;

import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;

public class WX_TemplateMsgUtil {

    private static Logger log = LoggerFactory.getLogger(WX_TemplateMsgUtil.class);

    /**
     * 封裝模板詳細信息
     * @return
     */
    public static JSONObject packJsonmsg(Map<String, TemplateData> param) {
        JSONObject json = new JSONObject();
        for (Map.Entry<String,TemplateData> entry : param.entrySet()) {
            JSONObject keyJson = new JSONObject();
            TemplateData  dta=  entry.getValue();
            keyJson.put("value",dta.getValue());
            keyJson.put("color", dta.getColor());
            json.put(entry.getKey(), keyJson);
        }
        return json;
    }

    /**
     * 根據模板的編號 新增並獲取模板ID
     * @param templateSerialNumber 模板庫中模板的 "編號"
     * @return 模板ID
     */
    public static String getWXTemplateMsgId(String templateSerialNumber){
        String tmpurl = "https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token="+ WX_TokenUtil.getWXToken().getAccessToken();
        JSONObject json = new JSONObject();
        json.put("template_id_short", templateSerialNumber);
        JSONObject result = WX_HttpsUtil.httpsRequest(tmpurl, "POST", json.toString());
        JSONObject resultJson = new JSONObject(result);
        String errmsg = (String) resultJson.get("errmsg");
        log.info("獲取模板編號返回信息:" + errmsg);
        if(!"ok".equals(errmsg)){
            return "error";
        }
        String templateId = (String) resultJson.get("template_id");
        return templateId;
    }

    /**
     * 根據模板ID 刪除模板消息
     * @param templateId 模板ID
     * @return
     */
    public static String deleteWXTemplateMsgById(String templateId){
        String tmpurl = "https://api.weixin.qq.com/cgi-bin/template/del_private_template?access_token="+ WX_TokenUtil.getWXToken().getAccessToken();
        JSONObject json = new JSONObject();
        json.put("template_id", templateId);
        try{
            JSONObject result = WX_HttpsUtil.httpsRequest(tmpurl, "POST", json.toString());
            JSONObject resultJson = new JSONObject(result);
            log.info("刪除"+templateId+"模板消息,返回CODE:"+ resultJson.get("errcode"));
            String errmsg = (String) resultJson.get("errmsg");
            if(!"ok".equals(errmsg)){
                return "error";
            }
        }catch(Exception e){
         e.printStackTrace();
        }
        return "success";
    }


    /**
     * 發送微信消息(模板消息)
     * @param touser 用戶 OpenID
     * @param templatId 模板消息ID
     * @param clickurl URL置空,則在發送後,點擊模板消息會進入一個空白頁面(ios),或無法點擊(android)。
     * @param topcolor 標題顏色
     * @param data 詳細內容
     * @return
     */
    public static String sendWechatMsgToUser(String touser, String templatId, String clickurl, String topcolor, JSONObject data) {
        String tmpurl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+ WX_TokenUtil.getWXToken().getAccessToken();
        JSONObject json = new JSONObject();
        json.put("touser", touser);
        json.put("template_id", templatId);
        json.put("url", clickurl);
        json.put("topcolor", topcolor);
        json.put("data", data);
        try{
            JSONObject result = WX_HttpsUtil.httpsRequest(tmpurl, "POST", json.toString());
            JSONObject resultJson = new JSONObject(result);
            log.info("發送微信消息返回信息:" + resultJson.get("errcode"));
            String errmsg = (String) resultJson.get("errmsg");
            if(!"ok".equals(errmsg)){  //如果爲errmsg爲ok,則代表發送成功,公衆號推送信息給用戶了。
                return "error";
            }
         }catch(Exception e){
            e.printStackTrace();
            return "error";
        }
//         finally {
//            if(templatId!=null) {
//                //刪除新增的 微信模板
//                deleteWXTemplateMsgById(templatId);
//            }
//        }
        return "success";
   }

}

package weixin.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;


public class WX_TokenUtil {

    private static Logger log = LoggerFactory.getLogger(WX_TokenUtil.class);
       /**
         *  獲得微信 AccessToken
         * access_token是公衆號的全局唯一接口調用憑據,公衆號調用各接口時都需使用access_token。
         * 開發者需要access_token的有效期目前爲2個小時,需定時刷新,重複獲取將導致上次獲取
         * 的access_token失效。  
         * (此處我是把token存在java緩存裏面了)此代碼token沒有加入緩存,後面附了緩存的工具類,根據需求自己添加
         */

        public static AccessToken getWXToken() {

            String appId="****************";
            String appSecret="****************";
            String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ appId+"&secret="+ appSecret;
                JSONObject jsonObject = WX_HttpsUtil.httpsRequest(tokenUrl, "GET", null);
                System.out.println("jsonObject:"+jsonObject);
                AccessToken access_token = new AccessToken();
                if (null != jsonObject) {
                    try {
                        access_token.setAccessToken(jsonObject.getString("access_token"));
                        access_token.setExpiresin(jsonObject.getInteger("expires_in"));
                    } catch (JSONException e) {
                        access_token = null;
                        // 獲取token失敗
                        log.error("獲取token失敗 errcode:{} errmsg:{}", jsonObject.getInteger("errcode"), jsonObject.getString("errmsg"));
                    }
                }
            return access_token;
        }

}

package weixin.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;

public class WX_UserUtil {
     private static Logger log = LoggerFactory.getLogger(WX_UserUtil.class);
        /**
         * 根據微信openId 獲取用戶是否訂閱
         * @param openId 微信openId
         * @return 是否訂閱該公衆號標識
         */
        public static Integer subscribeState(String openId){
            String tmpurl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+WX_TokenUtil.getWXToken().getAccessToken() +"&openid="+openId;
            JSONObject result = WX_HttpsUtil.httpsRequest(tmpurl, "GET",null);
            JSONObject resultJson = new JSONObject(result);
            log.error("獲取用戶是否訂閱 errcode:{} errmsg:{}", resultJson.getInteger("errcode"), resultJson.getString("errmsg"));
            String errmsg = (String) resultJson.get("errmsg");
            
            System.out.println(errmsg);
            if(errmsg==null){
                //用戶是否訂閱該公衆號標識(0代表此用戶沒有關注該公衆號 1表示關注了該公衆號)。
                Integer subscribe = (Integer) resultJson.get("subscribe");
                return subscribe;
            }
            return 0;
        }
        
        
        public static JSONObject getUserInfo(String openId){
            String tmpurl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+WX_TokenUtil.getWXToken().getAccessToken() +"&openid="+openId;
            JSONObject result = WX_HttpsUtil.httpsRequest(tmpurl, "GET",null);
            JSONObject resultJson = new JSONObject(result);
            log.error("獲取用戶是否訂閱 errcode:{} errmsg:{}", resultJson.getInteger("errcode"), resultJson.getString("errmsg"));
            String errmsg = (String) resultJson.get("errmsg");
            return resultJson;
        }
}

package cache.util;

import java.util.Calendar;  
import java.util.Map;  
import java.util.Set;  
import java.util.Timer;  
import java.util.TimerTask;  
import java.util.concurrent.ConcurrentHashMap;  
/** 
 * 簡單內存緩存管理器 
 * 可設置過期時間,單位毫秒 
 * 使用Timer定時清理過期數據,每分鐘清理一次,可修改清理週期 
 * @author Kevin
 * @datetime 2018年4月16日 下午5:18:50 
 */  
public class CacheManager {  
  
    @SuppressWarnings("rawtypes")  
    private static Map<String, CacheData> cache = new ConcurrentHashMap();  
      
    /** 
     * 啓動定時任務清理過期緩存,避免內存溢出 
     */  
    static {  
        Timer t = new Timer();  
        t.schedule(new ClearTimerTask(cache), 0, 7000 * 1000);  
    }  
      
    /** 
     * 設置緩存,不過期 
     * @param key 
     * @param t 
     */  
    public static <T> void set(String key, T t) {  
        cache.put(key, new CacheData(t, 0));  
    }  
      
    /** 
     * 設置緩存,指定過期時間expire(單位毫秒) 
     * @param key 
     * @param t 
     * @param expire 過期時間 
     */  
    public static <T> void set(String key, T t, long expire) {  
        cache.put(key, new CacheData(t, expire));  
    }  
      
    /** 
     * 根據key獲取指定緩存 
     * @param key 
     * @return 
     */  
    @SuppressWarnings("unchecked")  
    public static <T> T get(String key) {  
        CacheData<T> data = cache.get(key);  
        if(null == data) {  
            return null;  
        }  
        if(data.isExpire()) {  
            remove(key);  
            return null;  
        }  
        return data.getData();  
    }  
      
    /** 
     * 移除指定key緩存 
     * @param key 
     */  
    public static void remove(String key) {  
        cache.remove(key);  
    }  
      
    /** 
     * 移除所有緩存 
     */  
    public static void removeAll() {  
        cache.clear();  
    }  
      
    private static class CacheData<T> {  
        // 緩存數據  
        private T data;  
        // 過期時間(單位,毫秒)  
        private long expireTime;  
          
        public CacheData(T t, long expire) {  
            this.data = t;  
            if(expire <= 0) {  
                this.expireTime = 0L;  
            } else {  
                this.expireTime = Calendar.getInstance().getTimeInMillis() + expire;  
            }  
        }  
          
        /** 
         * 判斷緩存數據是否過期 
         * @return true表示過期,false表示未過期 
         */  
        public boolean isExpire() {  
            if(expireTime <= 0) {  
                return false;  
            }  
            if(expireTime > Calendar.getInstance().getTimeInMillis()) {  
                return false;  
            }  
            return true;  
        }  
          
        public T getData() {  
            return data;  
        }  
    }  
      
    /** 
     * 清理過期數據定時任務 
     * @author zsc 
     * @datetime 2018年2月9日 上午10:41:18 
     */  
    private static class ClearTimerTask extends TimerTask {  
  
        @SuppressWarnings("rawtypes")  
        Map<String, CacheData> cache;  
          
        @SuppressWarnings("rawtypes")  
        public ClearTimerTask(Map<String, CacheData> cache) {  
            this.cache = cache;  
        }  
          
        @Override  
        public void run() {  
            Set<String> keys = cache.keySet();  
            for(String key : keys) {  
                CacheData<?> data = cache.get(key);  
                if(data.expireTime <= 0) {  
                    continue;  
                }  
                if(data.expireTime > Calendar.getInstance().getTimeInMillis()) {  
                    continue;  
                }  
                cache.remove(key);  
            }  
        }  
    }  
}  

最後進行測試發送推送消息
package weixin.util;

import java.util.HashMap;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;


public class TestWX {
    public static void main(String[] args) {
        //新增用戶成功 - 推送微信消息
        senMsg("openid 以及幾個需要的模板消息參數,這個根據自己需求來修改");
    }
   public static void senMsg(String openId,String name,String event,String times,String remark){
        //用戶是否訂閱該公衆號標識 (0代表此用戶沒有關注該公衆號 1表示關注了該公衆號)
        Integer  state= WX_UserUtil.subscribeState(openId);
        System.out.println("state:"+state);
        // 綁定了微信並且關注了服務號的用戶 , 註冊成功-推送註冊短信
        if(state==1){
            Map<String,TemplateData> param = new HashMap();
            param.put("first",new TemplateData("您好,親愛的"+name+"!","#EE0000"));
            param.put("keyword1",new TemplateData(event,"#EE0000"));
            param.put("keyword2",new TemplateData(times,"#EE0000"));
            param.put("remark",new TemplateData(remark,"#EE0000"));
            //註冊的微信-模板Id
//            String regTempId =  WX_TemplateMsgUtil.getWXTemplateMsgId("TM00464");

            JSON.toJSONString(param);
            JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(param));
            //調用發送微信消息給用戶的接口    ********這裏寫自己在微信公衆平臺拿到的模板ID
          WX_TemplateMsgUtil.sendWechatMsgToUser(openId, ***********************************, "", 
                  "#000000", jsonObject);


          //獲取公衆號的自動回覆規則
          String urlinfo="https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info?access_token="+WX_TokenUtil.getWXToken().getAccessToken();
          JSONObject joinfo = WX_HttpsUtil.httpsRequest(urlinfo, "GET", null);
          Object o=joinfo.get("is_add_friend_reply_open");
         // System.out.println("o:"+joinfo);
          String getTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
            JSONObject Token = WX_HttpsUtil.httpsRequest(getTokenUrl, "GET", null);
            System.out.println("Token:"+Token);
        }
    }

}

此時你應該可以成功推送消息了.如上代碼我確保都是經過測試的,完全可以使用沒有問題

帖子寫的匆忙,如果任何疑問,請聯繫464744895




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章