Java微信分享接口開發

Java微信分享,步驟是

1、根據當前的url,獲取signature,nonceStr,timestamp 和appId。
2、通過signature,nonceStr,timestamp 和appId來配置微信 wx.config。
3、通過wx.ready實現微信分享功能。

1、html端

引入微信JS-SDK.

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

//分享核心js代碼
$(document).ready(function () {
	//通過ajax,在頁面加載的時候獲取微信分享接口signature,nonceStr,timestamp 和appId
    $.ajax({
        type: "post",
        url: "/weixin/share",
        dataType: "json",
        data:"url="+window.location.href,
        success: function (data) {
            wx.config({
                debug: false,
                appId: data.appId,
                timestamp: data.timestamp,
                nonceStr: data.nonceStr,
                signature: data.signature,
                jsApiList: ['onMenuShareAppMessage', 'onMenuShareTimeline', 'hideAllNonBaseMenuItem', 'showMenuItems']
                // 功能列表,我們要使用JS-SDK的什麼功能
            });
            wx.ready(function () {
                // 獲取“分享給朋友”按鈕點擊狀態及自定義分享內容接口
                wx.onMenuShareAppMessage({
                    title: "分享自定義標題", // 分享標題
                    desc: "分享自定義描述", // 分享描述
                    link: "http://localhost/weixin/share?openId=1",//分享點擊之後的鏈接
                    imgUrl:'/images/photo/1.jpg', // 分享圖標
                    type: 'link', // 分享類型,music、video或link,不填默認爲link
                    success: function () {
						//成功之後的回調
                    }
                });
                wx.hideAllNonBaseMenuItem();
                wx.showMenuItems({
                    menuList: ['menuItem:share:appMessage', 'menuItem:share:timeline'] // 要隱藏的菜單項,只能隱藏“傳播類”和“保護類”按鈕,所有menu項見附錄3
                });
                wx.onMenuShareTimeline({
                    title: "分享自定義標題", // 分享標題
                    desc: "分享自定義描述", // 分享描述
                    link: "http://localhost/weixin/share?openId=1",//分享點擊之後的鏈接
                    imgUrl:'/images/photo/1.jpg', // 分享圖標
                    type: 'link', // 分享類型,music、video或link,不填默認爲link
                    success: function () {
						//成功之後的回調
                    }
                    cancel: function () {
                        // 用戶取消分享後執行的回調函數
                    }
                });
            });
            wx.error(function (res) {
                //打印錯誤消息。及把 debug:false,設置爲debug:ture就可以直接在網頁上看到彈出的錯誤提示
            });
        }
    })
});

2、Java代碼,獲取 signature,nonceStr,timestamp 和appId

    @RequestMapping(value = "/share", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> share(HttpServletRequest request) {
        String urlTemp = "http://" + request.getServerName() + request.getContextPath();
        String urlpath = "http://" + request.getServerName();
        String appUrl = request.getParameter("url");
        if (request.getParameter("code") != null) {
            appUrl += "&code=" + request.getParameter("code");
        }
        if (request.getParameter("state") != null) {
            appUrl += "&state=" + request.getParameter("state");
        }
        return WxConfigUtil.getSignature(appUrl, ContentValues.APPID, ContentValues.SECRET, urlTemp, urlpath);
    }

工具類我就把整個貼上來了,其中有些方法是沒有用到的。

getSignature()整個方法是微信分享中的核心方法,用來獲取signature,nonceStr,timestamp 和appId這幾個核心參數。

package com.blog.common.util;

import com.alibaba.fastjson.JSONObject;
import com.blog.common.model.Token;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
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.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


/**
 * 公衆平臺通用接口工具類
 *
 * @author james
 * @date 2015-02-27
 */
public class WxConfigUtil {
    // 獲取access_token的接口地址(GET) 限2000(次/天)
    public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    // 獲取jsapi_ticket的接口地址(GET) 限2000(次/天)
    public final static String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
    // 緩存添加的時間
    public static String cacheAddTime = null;
    // token,ticket緩存
    public static Map<String, Token> TOKEN_TICKET_CACHE = new HashMap<String, Token>();
    // token對應的key
    private static final String TOKEN = "token";
    // ticket對應的key
    private static final String TICKET = "ticket";

    /**
     * 外部獲取簽名入口類
     *
     * @param appUrl    應用的url
     * @return
     */
    public static Map<String, Object> getSignature(String appUrl, String appId, String secret, String url, String urlpath) {
        // 生成簽名的隨機串
        String noncestr = RandomUtil.getStringRandom(4);
        if (appUrl == null || "".equals(appUrl)) {
            return null;
        }
        String signature = null;
        Token accessTocken = getToken(appId, secret, System.currentTimeMillis() / 1000);
        Token accessTicket = getTicket(accessTocken.getToken(), System.currentTimeMillis() / 1000);
        signature = signature(accessTicket.getTicket(), cacheAddTime, noncestr, appUrl);
        System.out.println("-=-=-=-=-=-=-=-=appUrl:" + appUrl);
        System.out.println("-=-=-=-=-=-=-=-=token:" + accessTocken.getToken());
        System.out.println("-=-=-=-=-=-=-=-=ticket:" + accessTicket.getTicket());
        System.out.println("-=-=-=-=-=-=-=-=signature:" + signature);
        System.out.println("-=-=-=-=-=-=-=-=timestamp:" + cacheAddTime);
        Map<String, Object> map = new HashMap<>();
        map.put("appId", appId);
        map.put("timestamp", cacheAddTime);
        map.put("nonceStr", noncestr);
        map.put("appUrl", appUrl);
        map.put("signature", signature);
        map.put("url", url);
        map.put("urlpath", urlpath);
        return map;
    }

    /**
     * 獲得Token
     *
     * @return
     */
    public static String getToken(String appId, String secret) {
        Token accessTocken = getToken(appId, secret, System.currentTimeMillis() / 1000);
        return accessTocken.getToken();
    }

    /**
     * 簽名
     *
     * @param timestamp
     * @return
     */
    private static String signature(String jsapi_ticket, String timestamp, String noncestr, String url) {
        jsapi_ticket = "jsapi_ticket=" + jsapi_ticket;
        timestamp = "timestamp=" + timestamp;
        noncestr = "noncestr=" + noncestr;
        url = "url=" + url;
        String[] arr = new String[]{jsapi_ticket, noncestr, timestamp, url};
        // 將token、timestamp、nonce,url參數進行字典序排序
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
            if (i != arr.length - 1) {
                content.append("&");
            }
        }
        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;
        return tmpStr;
    }

    /**
     * 獲取access_token
     *
     * @param appid     憑證
     * @param appsecret 密鑰
     * @return
     */
    public static Token getToken(String appid, String appsecret, long currentTime) {
        Token tockenTicketCache = getTokenTicket(TOKEN);
        Token Token = null;

        if (tockenTicketCache != null && (currentTime - tockenTicketCache.getAddTime() <= tockenTicketCache.getExpiresIn())) {// 緩存存在並且沒過期
            System.out.println("==========緩存中token已獲取時長爲:" + (currentTime - tockenTicketCache.getAddTime()) + "毫秒,可以重新使用");
            return tockenTicketCache;
        }
        System.out.println("==========緩存中token不存在或已過期===============");
        String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
        JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
        // 如果請求成功
        if (null != jsonObject) {
            Token = new Token();
            Token.setToken(jsonObject.getString("access_token"));
            Token.setExpiresIn(jsonObject.getIntValue("expires_in") / 2);// 正常過期時間是7200秒,此處設置3600秒讀取一次
            System.out.println("==========tocket緩存過期時間爲:" + Token.getExpiresIn() + "毫秒");
            Token.setAddTime(currentTime);
            updateToken(TOKEN, Token);
        }
        return Token;
    }

    /**
     * 獲取ticket
     *
     * @param token
     * @return
     */
    private static Token getTicket(String token, long currentTime) {
        Token tockenTicketCache = getTokenTicket(TICKET);
        Token Token = null;
        if (tockenTicketCache != null && (currentTime - tockenTicketCache.getAddTime() <= tockenTicketCache.getExpiresIn())) {// 緩存中有ticket
            System.out.println("==========緩存中ticket已獲取時長爲:" + (currentTime - tockenTicketCache.getAddTime()) + "毫秒,可以重新使用");
            return tockenTicketCache;
        }
        System.out.println("==========緩存中ticket不存在或已過期===============");
        String requestUrl = jsapi_ticket_url.replace("ACCESS_TOKEN", token);
        JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
        // 如果請求成功
        if (null != jsonObject) {
            Token = new Token();
            Token.setTicket(jsonObject.getString("ticket"));
            Token.setExpiresIn(jsonObject.getIntValue("expires_in") / 2);// 正常過期時間是7200秒,此處設置3600秒讀取一次
            System.out.println("==========ticket緩存過期時間爲:" + Token.getExpiresIn() + "毫秒");
            Token.setAddTime(currentTime);
            updateToken(TICKET, Token);
        }
        return Token;
    }

    /**
     * 發起https請求並獲取結果
     *
     * @param requestUrl    請求地址
     * @param requestMethod 請求方式(GET、POST)
     * @param outputStr     提交的數據
     * @return JSONObject(通過JSONObject.get(key)的方式獲取json對象的屬性值)
     */
    private static JSONObject httpRequest(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());
            // jsonObject = JSONObject.fromObject(buffer.toString());
        } catch (ConnectException ce) {
            System.out.println("Weixin server connection timed out.");
        } catch (Exception e) {
            System.out.println("https request error:{}" + e.getMessage());
        }
        return jsonObject;
    }

    /**
     * 將字節數組轉換爲十六進制字符串
     *
     * @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;
    }

    /**
     * 從緩存中讀取token或者ticket
     *
     * @return
     */
    private static Token getTokenTicket(String key) {
        if (TOKEN_TICKET_CACHE != null && TOKEN_TICKET_CACHE.get(key) != null) {
            System.out.println("==========從緩存中獲取到了" + key + "成功===============");
            return TOKEN_TICKET_CACHE.get(key);
        }
        return null;
    }

    /**
     * 更新緩存中token或者ticket
     *
     * @return
     */
    private static void updateToken(String key, Token accessTocken) {
        if (TOKEN_TICKET_CACHE != null && TOKEN_TICKET_CACHE.get(key) != null) {
            TOKEN_TICKET_CACHE.remove(key);
            System.out.println("==========從緩存中刪除" + key + "成功===============");
        }
        TOKEN_TICKET_CACHE.put(key, accessTocken);
        cacheAddTime = String.valueOf(accessTocken.getAddTime());// 更新緩存修改的時間
        System.out.println("==========更新緩存中" + key + "成功===============");
    }

}

由於大家都希望能看到分享微信的核心代碼,關於微信分享功能代碼及微信其他的核心功能代碼
已分享在自己的個人博客網站了 https://dingyinwu.com 在資源共享頁面,其中還有其它的一些資源~

發佈了62 篇原創文章 · 獲贊 80 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章